2010-09-10 15 views
27

Noté que la posición de titleView depende del título del botón rightbar. ¿Cómo puedo configurar el marco de titleView para que esté en el centro?¿Cómo ajustar el marco de navigationItem.titleView?

He intentado configurar titleView.frame, pero fue en vano.

Aquí está el código:

UIButton *titleLabel = [UIButton buttonWithType:UIButtonTypeCustom]; 
[titleLabel setTitle:@"Right Eye" forState:UIControlStateNormal]; 
[titleLabel setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 
[titleLabel setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted]; 
titleLabel.frame = CGRectMake(100, 0, 180, 44); 
titleLabel.titleLabel.backgroundColor = [UIColor clearColor]; 
titleLabel.titleLabel.font = [UIFont boldSystemFontOfSize:20.0]; 
titleLabel.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.3]; 
// titleLabel.titleLabel.textAlignment = UITextAlignmentCenter; (this doesn't work either) 
[titleLabel addTarget:self action:@selector(titleTap:) forControlEvents:UIControlEventTouchUpInside]; 
self.navigationItem.titleView = titleLabel; 
self.navigationItem.titleView.frame = CGRectMake(100, 0, 180, 44); //(this doesn't work either) 

alt text

+0

alguien? alguien ayuda! –

+0

¡Estoy teniendo el mismo problema! Los botones en el lado izquierdo o derecho están causando la recentered de titleView, incluso después de que lo configuré exactamente en layoutSubviews – quantumpotato

Respuesta

46

En algún momento entre la vista del controlador de vista aparecerá: & viewDidAppear :, la barra de navegación está reposicionando su titleView y cambiando el tamaño para caber si es necesario. Puede terminar sin centrar porque la barra de navegación prefiere no cambiar el tamaño de su titleView para que quepa entre los botones. Parece que intenta centrar la vista del título si es lo suficientemente pequeña, pero si no, moverá el título fuera del centro, y entonces creo que solo como último recurso se cambiará el tamaño. El efecto es que titleView está ocupando todo el espacio entre los dos botones, si su textoAlineación está centrada, entonces se centrará en ese espacio aunque no centrado con respecto a toda la pantalla. Puedes ver esto en tu captura de pantalla.

Una respuesta es hacer que su titleView sea más estrecho para que la barra de navegación pueda centrarlo, así que intente con 160 en lugar de 180 cuando configure su titleView.frame. Es una mierda que, al crear la vista programáticamente como usted, uno tiene que poner una estimación para ese ancho en el código. Lo que sería bueno es una forma de maximizar ese espacio mientras se mantiene centrado.

Es posible comenzar con titleView siendo el ancho de la pantalla, luego, después de que la barra de navegación cambie titleView.frame, actualizarlo nuevamente usted mismo en la vista del controlador de vistaDidAppear :. Usando sus títulos ajustados View.frame.origin.x y size.width junto con el ancho de la pantalla, puede calcular los márgenes derechos más grandes de la izquierda &, luego establezca el origen.x en ese, el tamaño. ancho en el ancho de la pantalla menos esos tiempos 2. Sin embargo, eso no surte efecto hasta después de que la vista presionada se haya animado y el cambio posterior sea visible. Podría ocultar el titleView en viewWillAppear: luego mostrarlo en viewDidAppear: después de centrarlo, de modo que en lugar de deslizarse hacia adentro con un titleView descentrado que luego se desplaza, se deslizaría sin ningún título que aparezca.

Una mejor posibilidad es hacer que su títuloVer su propia subclase de UIView (o UILabel o lo que sea) y anular setFrame para cambiar el tamaño para mantenerse centrado en su supervista. Si alguna vez termino haciéndolo yo mismo, lo publicaré aquí. O tal vez alguien más sepa otro lugar para cambiar el marco de titleView después de su actualización, pero antes de que la vista se deslice sin una subclase de vista.

+2

Esto realmente debería marcarse como la respuesta. Al usar esto, hice que el ancho de mi vista fuera exactamente lo que necesitaba para ajustarse al texto de mi etiqueta. Esto funcionó muy bien! – GendoIkari

+0

Gracias por escribir esta respuesta, me ayudó mucho. –

+0

Hice una observación en la propiedad frame de navigationBar e hice lo que sugirió cuando el marco de navigationBar cambió. En mi caso, el problema ocurrió en los cambios de orientación. –

0

mismo problema aquí. Implementando etiqueta de desplazamiento automático como titleView. Para que el texto largo en el título de navegación se pueda desplazar automáticamente para que el usuario lo vea todo. Todos los problemas con dimensiones reales desconocidas de titleView previenen el centrado de texto en el caso especial más simple: cuando el texto de la etiqueta se ajusta y no es necesario el desplazamiento automático (como establecer el texto en la propiedad title de navigationItem).

1
-(void) awakeFromNib 
{ 
    UIButton *titleLabel = [UIButton buttonWithType:UIButtonTypeCustom]; 
    [titleLabel setTitle:@"Right Eye" forState:UIControlStateNormal]; 
    [titleLabel setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 
    [titleLabel setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted]; 
    titleLabel.titleLabel.backgroundColor = [UIColor clearColor]; 
    titleLabel.titleLabel.font = [UIFont boldSystemFontOfSize:20.0]; 
    titleLabel.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.3]; 
    [titleLabel addTarget:self action:@selector(titleTap:) forControlEvents:UIControlEventTouchUpInside]; 
    titleLabel.frame = CGRectMake(0, 0, 400, 20); 
    self.navigationItem.titleView = titleLabel; 

} 
+1

No llame a la versión en un objeto Autorelease ... – Lolloz89

17

Después de configurar su titleview o TitleLabel, llame sizeToFit en él, también asegurarse de titleLabel.textAlignment = UITextAlignmentCenter. Se centrará en el ancho de la barra de navegación en lugar de en el espacio entre el borde del botón y el extremo de la barra de navegación.

+1

esto simplemente funciona. cuando leí la respuesta por primera vez, leí la respuesta larga, "imposible", y tuve miedo. esto debería marcarse como el correcto. – shem

+0

Esto funciona bastante bien. También funciona en otras UIViews, como UIButton. –

12

Ninguna de las sugerencias aquí realmente funcionó para mí.Mi problema era que estaba configurando TitleView mientras la barra de navegación estaba en el medio de su transición: me daría esta extraña trepidación, donde el título View parpadearía hacia la izquierda, y luego terminaría en el centro.

terminé siguiente idea primordial y setFrame de smallduck, era tan simple como:

- (void)setFrame:(CGRect)frame { 
    [super setFrame:CGRectMake(0, 0, self.superview.bounds.size.width, self.superview.bounds.size.height)]; 
} 
+0

funcionó al instante! –

1

Mi solución fue cambiar manualmente el tamaño de la barra de navegación en viewDidAppear:

- (void)viewDidAppear 
{ 
    [super viewDidAppear]; 
    [self.navigationController.navigationBar setFrame:CGRectMake(x, y, width, height)]; 
} 

... después de eso puede cambiar la posición de la vista del título también. Me di cuenta de que el problema principal era el hecho de que la barra de navegación también había cambiado de tamaño, así que volví a su tamaño normal. Obtuve el tamaño normal de la depuración y comprobé su tamaño en viewDidLoad antes de que se modificara ...

+0

No es una buena opción opción –

+0

Esta fue la solución más cercana que funcionó para mí. Tuve que hacer una declaración de cambio basada en la imagen del botón que podría variar según lo que haya seleccionado el usuario. Agarré la información del depurador sobre el tamaño y ajusté en consecuencia. – invertedfjord

6

Puede intentar establecer inicialmente el marco en CGRectZero y llamar a sizeToFit. A continuación se muestra el código que utilicé para cambiar el texto del título y me aseguré de que aún esté centrado. Tenía un botón de retroceso a la izquierda.

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];  
label.text = @"Title"; 
[label sizeToFit]; 
self.navigationItem.titleView = label; 
+0

en lugar de establecer el marco en CGRectZero, puede hacer 'UILabel * label = [[UILabel alloc] init];' –

0

Tengo un caso de uso ligeramente diferente (desplazamiento vertical de UIButton como titleView en iOS 7). Después de un largo tiempo, se me ocurrió utilizar la propiedad contentEdgeInsets de UIButton para cambiar el contenido de su marco.

0

La única forma que encontré en Reparar esto es no usar UINavigationItems. Insted utilizar dos puntos de vista diferentes en el lado botón eace del UINavigationBar así:

-(UIView *)rightButtonViewSection { 
    if (!_rightButtonViewSection) { 

     _rightButtonViewSection = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 45)]; 

    } 
    return _rightButtonViewSection; 

} 

-(UIView *)leftButtonViewSection { 
    if (!_leftButtonViewSection) { 

     _leftButtonViewSection = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 45)]; 

    } 
    return _leftButtonViewSection; 

} 

y setButtons en él de este modo:

ButtonBase *searchButton = [[ButtonBase alloc] initWithFrame:CGRectMake(0, 0, 32, 30)]; 
    [searchButton setImage:[UIImage imageNamed:SEARCH_IMAGE] forState:UIControlStateNormal]; 
    SEL searchSelector = @selector(tradersSearchButtonPress); 
    [searchButton addTarget:self action:searchSelector forControlEvents:UIControlEventTouchUpInside]; 

    self.notificationButton.view.frame = [self rightButtonFrame]; 
    searchButton.frame = [self rightSecoundButtonFrame]; 

    [self.rightButtonViewSection removeAllSubviews]; 
    [self.rightButtonViewSection addSubview:self.notificationButton.view]; 
    [self.rightButtonViewSection addSubview:searchButton]; 

    UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithCustomView:self.rightButtonViewSection]; 
    self.topViewController.navigationItem.rightBarButtonItem = buttonItem; 

ButtonsFrames:

-(CGRect) rightButtonFrame { 
    return CGRectMake(self.rightButtonViewSection.width - 32, 7, 32, 30); 
} 
-(CGRect) rightSecoundButtonFrame { 
    return CGRectMake(self.rightButtonViewSection.width - 80, 7, 32, 30); 
} 

A continuación, el título se ¡no moverse! porque los UIButtonsViews tienen el mismo ancho.

-1

Sólo tiene que añadir botón invisible (sin texto) en el lado derecho de la barra de navegación, y cambiar su tamaño a por ejemplo 20 px

0

que estaba poniendo en práctica un título de dos filas similar a algo WhatsApp está haciendo (título y subtítulo) .

He resuelto este problema mediante la subclase UINavigationController y anulando viewDidLayoutSubviews().

Mi titleview tiene el siguiente (en un viewController):

let frame = self.navigationController?.navigationBar.bounds ?? CGRect.zero 

// This is a container view for the two labels, laying them out vertically 
let titleView = UIStackView(arrangedSubviews: [self._titleLabel, self._promptLabel]) 
titleView.axis = .vertical 
titleView.alignment = .center 
titleView.distribution = .fill 
titleView.frame = frame // set the frame to the navbarFrame initially 
titleView.spacing = 0 

// The wrapper is necessary for laying out the stackView as the titleView 
let wrapperView = UIView(frame: frame) 
wrapperView.addSubview(titleView) 

self.navigationItem.titleView = wrapperView 

Mi viewDidLayoutSubviews():

guard let navigationItem = self.topViewController?.navigationItem, 
     let titleView = navigationItem.titleView, 
     let wrapperView = titleView.subviews[0] as? UIStackView else { return } 

var width : CGFloat = 0 

for view in wrapperView.arrangedSubviews { 
    view.sizeToFit() 
    width = max(width, view.frame.size.width) 
} 

titleView.frame.size.width = width 
titleView.frame.size.height = self.navigationBar.frame.height 
wrapperView.frame = titleView.bounds 
wrapperView.center.x = self.navigationBar.convert(self.navigationBar.center, to: titleView).x 
wrapperView.center.y = titleView.frame.height/2 

self.navigationBar.layoutIfNeeded() 

Nota: El truco es tener una visión envoltura alrededor de su titleview cuales puede ser presentado por la barra de navegación. Luego ajuste el marco de su titleView a lo que desea.

0

Recientemente me enfrento con el mismo problema, tengo una vista de título compleja cuyo contenido puede cambiar, así que quiero mostrar más contenido, el botón izquierdo y el botón derecho tienen un ancho diferente, por lo que Configuré un ancho largo, la barra de navegación no lo centrará. Como es posible que sepa cuando el elemento del botón de la barra izquierda o derecha es muy largo, es imposible centrar la vista del título, por lo que quiero centrarlo tanto como sea posible.

Una vez que establecemos una vista en self.navigationItem.titleView, la barra de navegación administrará el marco de la vista de título, es difícil centrarlo directamente, por lo que subclase una vista que funciona como vista de contenedor de la vista de título real, configuré su ancho con la pantalla ancho, UINavigationBar con establecer su marco a un valor de propiedad respecto a su elemento de botón de barra izquierda/derecha.

La vista contenedor es MDLNavigationTitleContainer y la vista de un título real es MDLMessagesNavigationTitleView, MDLMessagesNavigationTitleView es administrado por el diseño de automóviles, ya que es súper vista es MDLNavigationTitleContainer, cada vez que sus cambios de ancho, layoutSubviews serán llamados. El código en layoutSubviews parece un poco extraño, se usa para manejar la animación push/pop.

@interface MDLNavigationTitleContainer() 

@property (nonatomic) CGRect oldFrame; 

@end 

@implementation MDLNavigationTitleContainer 

- (instancetype)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     UINib *nib = [UINib nibWithNibName:@"MDLMessagesNavigationTitleView" bundle:[NSBundle bundleForClass:[MDLMessagesNavigationTitleView class]]]; 
     self.titleView = [[nib instantiateWithOwner:nil options:nil] firstObject]; 
     self.titleView.translatesAutoresizingMaskIntoConstraints = NO; 
     [self addSubview:self.titleView]; 
     NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; 
     NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; 
     NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0]; 
     width.priority = 200; 
     NSLayoutConstraint *width1 = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1 constant:0]; 
     [self addConstraint:centerX]; 
     [self addConstraint:centerY]; 
     [self addConstraint:width]; 
     [self addConstraint:width1]; 
    } 
    return self; 
} 

- (void)layoutSubviews { 
    [super layoutSubviews]; 

    if (!self.superview) { 
     return; 
    } 

    if (self.center.x > [UIScreen mainScreen].bounds.size.width) { 
     self.titleView.frame = self.oldFrame; 
     return; 
    } 

    CGFloat centerX = self.center.x; 

    CGFloat superWidth = [UIScreen mainScreen].bounds.size.width; 
    CGFloat superCenterX = superWidth/2; 
    CGFloat offsetX = superCenterX - centerX; 
    CGPoint center = self.titleView.center; 

    if (CGRectGetMaxX(self.titleView.frame) + offsetX < self.bounds.size.width && 
     CGRectGetMinX(self.titleView.frame) + offsetX > 0) { 
     center = CGPointMake(self.bounds.size.width/2 + offsetX, self.bounds.size.height/2); 
    } 
    CGSize size = self.titleView.bounds.size; 
    if (size.width > self.bounds.size.width) { 
     size.width = self.bounds.size.width; 
    } 

    self.titleView.frame = CGRectMake(center.x-size.width/2, center.y-size.height/2, size.width, size.height); 
    self.oldFrame = self.titleView.frame; 
} 

Establecer el título de la vista:

MDLNavigationTitleContainer *titleView = [[MDLNavigationTitleContainer alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)]; 
self.navigationItem.titleView = titleView; 
Cuestiones relacionadas