vertical raywenderlich objective how example buttons ios objective-c uistackview ios11

raywenderlich - Espaciador negativo para UIBarButtonItem en la barra de navegación en iOS 11



uistackview swift programmatically (4)

En iOS 10 y versiones anteriores, había una manera de agregar un espaciador negativo a la matriz de botones en la barra de navegación, de esta manera:

UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; negativeSpacer.width = -8; self.navigationItem.leftBarButtonItems = @[negativeSpacer, [self backButtonItem]];

Esto ya no funciona en iOS 11 (el espaciador se vuelve positivo, en lugar de negativo). He inspeccionado la jerarquía de vistas del elemento del botón de la barra y ahora está incrustado en _UIButtonBarStackView . ¿Cómo ajustar la posición del botón de barra en iOS 11?


Basándome en la respuesta de keithbhunter, he creado una barra UINavigation personalizada:

NavigationBarCustomMargins.h:

#import <UIKit/UIKit.h> @interface NavigationBarCustomMargins : UINavigationBar @property (nonatomic) IBInspectable CGFloat leftMargin; @property (nonatomic) IBInspectable CGFloat rightMargin; @end

NavigationBarCustomMargins.m:

#import "NavigationBarCustomMargins.h" #define DefaultMargin 16 #define NegativeSpacerTag 87236223 @interface NavigationBarCustomMargins () @property (nonatomic) BOOL leftMarginIsSet; @property (nonatomic) BOOL rightMarginIsSet; @end @implementation NavigationBarCustomMargins @synthesize leftMargin = _leftMargin; @synthesize rightMargin = _rightMargin; - (void)layoutSubviews { [super layoutSubviews]; if (([[[UIDevice currentDevice] systemVersion] compare:@"11.0" options:NSNumericSearch] != NSOrderedAscending)) { BOOL isRTL = [UIApplication sharedApplication].userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft; for (UIView *view in self.subviews) { view.layoutMargins = UIEdgeInsetsMake(0, isRTL ? self.rightMargin : self.leftMargin, 0, isRTL ? self.leftMargin : self.rightMargin); } } else { //left NSMutableArray *leftItems = [self.topItem.leftBarButtonItems mutableCopy]; if (((UIBarButtonItem *)leftItems.firstObject).tag != NegativeSpacerTag) { UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; negativeSpacer.tag = NegativeSpacerTag; negativeSpacer.width = self.leftMargin - DefaultMargin; [leftItems insertObject:negativeSpacer atIndex:0]; [self.topItem setLeftBarButtonItems:[leftItems copy] animated:NO]; } //right NSMutableArray *rightItems = [self.topItem.rightBarButtonItems mutableCopy]; if (((UIBarButtonItem *)rightItems.firstObject).tag != NegativeSpacerTag) { UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; negativeSpacer.tag = NegativeSpacerTag; negativeSpacer.width = self.rightMargin - DefaultMargin; [rightItems insertObject:negativeSpacer atIndex:0]; [self.topItem setRightBarButtonItems:[rightItems copy] animated:NO]; } } } - (CGFloat)leftMargin { if (_leftMarginIsSet) { return _leftMargin; } return DefaultMargin; } - (CGFloat)rightMargin { if (_rightMarginIsSet) { return _rightMargin; } return DefaultMargin; } - (void)setLeftMargin:(CGFloat)leftMargin { _leftMargin = leftMargin; _leftMarginIsSet = YES; } - (void)setRightMargin:(CGFloat)rightMargin { _rightMargin = rightMargin; _rightMarginIsSet = YES; } @end

Después de eso, establezco la clase personalizada a mi UINavigationController en Interface Builder y simplemente configuro los márgenes necesarios: Captura de pantalla 1

Funciona bien. Soporta RTL y iOS anteriores a 11: Captura de pantalla 2


Encontré una solución algo intrincada en los foros de desarrolladores de Apple: https://forums.developer.apple.com/thread/80075

Parece que el problema proviene de cómo iOS 11 maneja los botones UIBarButtonItem .fixedSpace y cómo se presenta una UINavigationBar en iOS 11. Las barras de navegación ahora usan autolayout y los márgenes de diseño para diseñar los botones. La solución presentada en esa publicación (en la parte inferior) fue establecer todos los márgenes de diseño en el valor que desee.

class InsetButtonsNavigationBar: UINavigationBar { override func layoutSubviews() { super.layoutSubviews() for view in subviews { // Setting the layout margins to 0 lines the bar buttons items up at // the edges of the screen. You can set this to any number to change // the spacing. view.layoutMargins = .zero } } }

Para usar esta nueva barra de navegación con espacio de botones personalizado, deberá actualizar el lugar donde cree los controladores de navegación con el siguiente código:

let navController = UINavigationController(navigationBarClass: InsetButtonsNavigationBar.self, toolbarClass: UIToolbar.self) navController.viewControllers = [yourRootViewController]


Para mí, esta respuesta ayuda https://.com/a/44896832
En particular, he configurado tanto imageEdgeInsets como titleEdgeInsets porque mi botón tiene imagen y título juntos


Solo una solución para mi caso, podría ser útil para algunas personas. Me gustaría lograr esto:

y previamente también estaba usando el separador negativo. Ahora me di cuenta de esta solución:

let logoImage = UIImage(named: "your_image") let logoImageView = UIImageView(image: logoImage) logoImageView.frame = CGRect(x: -16, y: 0, width: 150, height: 44) logoImageView.contentMode = .scaleAspectFit let logoView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 44)) **logoView.clipsToBounds = false** logoView.addSubview(logoImageView) let logoItem = UIBarButtonItem(customView: logoView) navigationItem.leftBarButtonItem = logoItem