iphone - navigation bar ios
¿Ajustando el marco de navigationItem.titleView? (12)
Noté que la posición de la vista de título depende del título del botón derecho. ¿Cómo puedo configurar el marco del titleView para que esté en el centro?
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)
Después de configurar su titleView o titleLabel, llame a sizeToFit
, también asegúrese de que titleLabel.textAlignment = UITextAlignmentCenter
. Se centrará en el ancho de la barra de navegación en lugar del espacio entre el borde del botón y el borde lejano de la barra de navegación.
El mismo problema aqui. Implementando la etiqueta de desplazamiento automático como titleView. De modo que el texto largo en el título de navegación podría desplazarse automáticamente para que el usuario lo vea todo. Todos los problemas con dimensiones reales desconocidas de titleView previenen el centrado del 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 del título de navigationItem).
En algún momento entre la vista del controlador de vista, aparecerá: & verDeAparecer:, la barra de navegación está reposicionando su vista de título y redimensionándola para que se ajuste si es necesario. Puede terminar sin centrarse porque la barra de navegación prefiere no cambiar el tamaño de su vista de título para que quepa entre los botones. Parece que trata de centrar la vista del título si es lo suficientemente pequeña, pero si no lo hace, moverá tu título Vista fuera del centro, y luego creo que solo se cambiará el tamaño del último recurso. El efecto es que titleView está ocupando todo el espacio entre los dos botones, si su alineación de texto está centrada, entonces se centrará en ese espacio aunque no esté centrado con respecto a toda la pantalla. Puedes ver esto en tu captura de pantalla.
Una respuesta es hacer que tu título de vista sea más estrecho para que la barra de navegación pueda centrarlo, así que prueba unos 160 en lugar de 180 cuando configuras tu título de vista. Apesta que, al crear la vista programáticamente como usted, uno tiene que poner una estimación de 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 el título de vista siendo el ancho de la pantalla, luego, después de que la barra de navegación cambie el archivo de vista de título, actualícelo nuevamente en viewDidAppear: del controlador de vista. Usando su titleView.frame.origin.x y size.width ajustados junto con el ancho de la pantalla, puede calcular el mayor de los márgenes izquierdo y derecho, luego establecer el origen.x a eso, el ancho.width de size al ancho de la pantalla menos that times 2. Sin embargo, eso no tendrá efecto hasta después de que la vista empujada se haya animado y el cambio posterior sea visible. Puede ocultar el título Ver en la vista. Aparecerá: luego mostrarse en la vista. Aparecer: después de centrarlo, así que en lugar de deslizarse con un título fuera del centro que se desplaza, se deslizará sin ningún título que luego aparecerá.
Una mejor posibilidad es hacer que su título vea su propia subclase de UIView (o UILabel o la que sea) y anule setFrame para redimensionarse para permanecer centrado en su supervisión. Si alguna vez termino haciendo esto, lo publicaré aquí. O tal vez alguien más conoce otro lugar para cambiar el marco del titleView después de que se haya actualizado pero antes de que la vista se deslice sin una subclase de vista.
Estaba implementando un título de dos filas similar a algo que está haciendo WhatsApp (título y subtítulo).
UINavigationController
este problema subclasificando UINavigationController
y anulando viewDidLayoutSubviews()
.
Mi titleView se parece a lo 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
My 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 consiste en tener una vista envolvente alrededor de su vista de título, que puede ser desplegada por la barra de navegación. Luego ajusta el marco de tu título de vista a lo que desees.
La única manera que encontré para corregir esto es no usar UINavigationItems. Insted usar dos vistas diferentes en el lado del botón eace de 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 como tal:
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;
Cuadros de botones:
-(CGRect) rightButtonFrame {
return CGRectMake(self.rightButtonViewSection.width - 32, 7, 32, 30);
}
-(CGRect) rightSecoundButtonFrame {
return CGRectMake(self.rightButtonViewSection.width - 80, 7, 32, 30);
}
Entonces el título no se moverá! Porque las UIButtonsViews tienen el mismo ancho.
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, también puedes reposicionar la vista del título. Acabo de darme cuenta de que el problema principal era el hecho de que la barra de navegación también se redimensionó, así que la devolví a su tamaño normal. Obtuve el tamaño regular de depuración y comprobación de su tamaño en viewDidLoad antes de que se modificara ...
Ninguna de las sugerencias aquí realmente funcionó para mí. Mi problema fue que estaba configurando titleView mientras la barra de navegación estaba en el medio de su transición: obtendría este extraño jitter en el que el titleView parpadearía hacia la izquierda y luego terminaría de nuevo en el centro.
Terminé siguiendo la idea de smallduck y reemplazando a setFrame, fue tan simple como:
- (void)setFrame:(CGRect)frame {
[super setFrame:CGRectMake(0, 0, self.superview.bounds.size.width, self.superview.bounds.size.height)];
}
Puede intentar establecer el marco en CGRectZero inicialmente 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;
Recientemente me enfrento con el mismo problema, tengo una vista de título compleja cuyo contenido puede cambiar, así que quiero poder mostrar el mayor contenido posible, mi elemento del botón de la barra izquierda y el elemento del botón de la barra derecha tienen un ancho diferente, así que si lo configuro De ancho, la barra de navegación no la centrará. Como es posible que sepa que 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 centrarla lo más posible.
Una vez que configuramos una vista para self.navigationItem.titleView
, la barra de navegación administrará el marco de la vista de título, es difícil centrarla directamente, así que subclase una vista que funciona como la vista de contenedor de la vista de título real, configuro su ancho con la pantalla ancho, UINavigationBar
con establece su marco en un valor de propiedad con respecto a su elemento de botón de barra izquierda / derecha.
La vista del contenedor es MDLNavigationTitleContainer
y la vista del título real es MDLMessagesNavigationTitleView
, MDLMessagesNavigationTitleView
es administrada por el diseño automático, ya que la vista super es MDLNavigationTitleContainer
, cada vez que se modifica el ancho, layoutSubviews
. El código en layoutSubviews
parece un poco extraño, se utiliza 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 la vista de título:
MDLNavigationTitleContainer *titleView = [[MDLNavigationTitleContainer alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
self.navigationItem.titleView = titleView;
Simplemente agregue un botón invisible (sin texto) en el lado derecho de la barra de navegación y cambie su tamaño a, por ejemplo, 20 px
Tengo un caso de uso ligeramente diferente (desplazamiento vertical de UIButton como titleView en iOS 7). Después de mucho tiempo se me ocurrió usar la propiedad contentEdgeInsets
de UIButton para cambiar el contenido en su marco.
-(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;
}