Cómo editar espacios vacíos de UIBarButtonItem izquierdo y derecho en UINavigationBar [iOS 7]

84

Estaba usando iOS 6.1 anteriormente, pero ahora me cambié a iOS 7. Junto con otros problemas, he observado que en mi barra de navegación, el espacio izquierdo del elemento del botón de la barra izquierda y el espacio vacío derecho del elemento de la barra del botón derecho son bastante más en IOS 7 que en iOS 6.

Necesito saber si hay alguna manera de reducir los espacios vacíos de los elementos del botón de la barra izquierda y derecha en la barra de navegación.

Gracias por adelantado.

Salman Zaidi
fuente
@devxoul, UINavigationItem-Margin tiene problemas con iOS14. He creado un problema para eso, si tiene alguna solución, consulte esto.
Kuldeep

Respuestas:

222

También estaba enfrentando este problema. También tengo la sensación de que en iOS 7 hay más espacio. Y me di cuenta de que esto es aproximadamente 10 puntos más. Normalmente utilizo espacios negativos cuando quiero LeftBarItemButtonempezar desde el borde. Esto también puede resultarle útil.

UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];

negativeSpacer.width = -16; // it was -6 in iOS 6

[self.navigationItem setLeftBarButtonItems:@[negativeSpacer, requiredButton]; /* this will be the button which you actually need */] animated:NO];
Adnan Aftab
fuente
4
Realmente funciona en iOS 7, ya que estoy usando esto en mi par de proyectos en este momento ... hay una diferencia en el sistema de puntos, así que tienes que encargarte de eso ...
Adnan Aftab
10
No funciona si lo hace [NSArray arrayWithObjects: requiredButton, negativeSpacer]. Cuidado con el orden.
Mert Buran
3
Funciona muy bien y tenga en cuenta que para rightBarButtonItems, el espaciador debe ser el primer elemento de la matriz si desea cambiar el margen derecho
leonaka
1
@C_X para iPhone 6, el margen de -16 no parece funcionar. -20 parece correcto ... ¿Alguna idea de cómo podemos hacer que esto funcione bien en todos los dispositivos iPhone?
Vignesh PT
1
@TheRohanSanap: un ancho positivo sería un espaciador que aumenta la cantidad de espacio vacío que hay antes del primer elemento visual. Este truco de un ancho negativo disminuye el espacio vacío.
ToolmakerSteve
23

Basado en @C_X su respuesta, he creado una categoría que agrega y posiciona el UIBarButtonItem según la versión de iOS del dispositivo actual.

// UINavigationItem+Additions.h
@interface UINavigationItem (Additions)
- (void)addLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem;
- (void)addRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem;
@end

// UINavigationItem+Additions.m
@implementation UINavigationItem (Additions)

- (void)addLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem
{
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        // Add a negative spacer on iOS >= 7.0
        UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                              target:nil action:nil];
        negativeSpacer.width = -10;
        [self setLeftBarButtonItems:[NSArray arrayWithObjects:negativeSpacer, leftBarButtonItem, nil]];
    } else {
        // Just set the UIBarButtonItem as you would normally
        [self setLeftBarButtonItem:leftBarButtonItem];
    }
}

- (void)addRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem
{
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        // Add a negative spacer on iOS >= 7.0
        UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc]
                                       initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                                       target:nil action:nil];
        negativeSpacer.width = -10;
        [self setRightBarButtonItems:[NSArray arrayWithObjects:negativeSpacer, rightBarButtonItem, nil]];
    } else {
        // Just set the UIBarButtonItem as you would normally
        [self setRightBarButtonItem:rightBarButtonItem];
    }
}

@end

En su controlador de vista ahora puede usar [self.navigationItem addLeftBarButtonItem:leftBarButtonItem];y[self.navigationItem addRightBarButtonItem:rightBarButtonItem];

También intenté subclasificar UIButtony anular, -alignmentRectInsetspero esto me dio problemas con las transiciones entre vistas.

olfato
fuente
10

Para Swift 2.0, esta fue mi solución para obtener el siguiente efecto ...

(los valores reales pueden ser diferentes, dependiendo de su situación)

ingrese la descripción de la imagen aquí

let captureButton = UIButton()
captureButton.setTitle("CAPTURE DETAILS", forState: .Normal)
captureButton.frame = CGRectMake(0, 0, 200, 95)
captureButton.addTarget(self, action: Selector("showCaptureDetailsForm:"), forControlEvents: .TouchUpInside) // *** See update below for Swift 2.2 syntax
captureButton.setBackgroundImage(UIImage(named: "blueTopRight"), forState: .Normal)
        
let rightBarButton = UIBarButtonItem()
rightBarButton.customView = captureButton        
        
let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
negativeSpacer.width = -25;
        
self.navigationItem.setRightBarButtonItems([negativeSpacer, rightBarButton ], animated: false)

ACTUALIZACIÓN Swift 2.2:

Para Swift 2.2, el action: Selectormétodo ha cambiado y debe escribirse de la siguiente manera

captureButton.addTarget(self, action: #selector(YourViewController.showCaptureDetailsForm(_:)), forControlEvents: .TouchUpInside)

Simón
fuente
9

Esta es mi solución para Swift 3.0:

rightBtn.imageInsets = UIEdgeInsets(top: 0, left: -13.0, bottom: 0, right: 13.0) 
self.navigationItem.rightBarButtonItem = rightBtn
tuandapen
fuente
6

Para corregir este error, debe crear una subclase UIButtonpara poder anular alignmentRectInsets. Según mis pruebas, deberá devolver un UIEdgeInsetscon un desplazamiento derecho positivo o un desplazamiento izquierdo positivo, según la posición del botón. Estos números no tienen sentido para mí (al menos uno de ellos debería ser negativo, según el sentido común), pero esto es lo que realmente funciona:

- (UIEdgeInsets)alignmentRectInsets {
    UIEdgeInsets insets;
    if (IF_ITS_A_LEFT_BUTTON) {
        insets = UIEdgeInsetsMake(0, 9.0f, 0, 0);
    } 
    else { // IF_ITS_A_RIGHT_BUTTON
        insets = UIEdgeInsetsMake(0, 0, 0, 9.0f);
    }
    return insets;
}

Un agradecimiento especial a @zev por sugerir que intente ajustar alignmentRectInsets.

jaredsinclair
fuente
gracias por la respuesta. Aunque es una buena solución, he preferido la respuesta @C_X porque en este momento estoy tratando de evitar la subclasificación ..
Salman Zaidi
Esto me causó algunos cambios extraños de los botones durante las animaciones en iOS 6, comenzarían en el lugar incorrecto y cambiarían para coincidir con las inserciones después de que se completara la animación.
Chris Wagner
No me sorprendería. El código anterior solo es necesario para obtener un diseño de estilo iOS 6 para compilaciones de iOS 7.
jaredsinclair
Solución rápida, buen trabajo. Sin embargo, para iOS 9, debe devolver las inserciones, no configurarlas:
A-Majeed
5

Siguiendo el ejemplo de smek, hice una categoría pero la modifiqué para proporcionar compatibilidad con versiones anteriores en lugar de con versiones posteriores. Configuro todo para que funcione como quiero en iOS 7 y luego, si el usuario está ejecutando algo más bajo, empiezo a estropear las cosas.

@interface UINavigationItem (BarButtonItemSpacingSupport)

- (void)addLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem;
- (void)addRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem;

@end

@implementation UINavigationItem (BarButtonItemSpacingSupport)

- (void)addLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem
{
    if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
        // Add a spacer on when running lower than iOS 7.0
        UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                                                                                        target:nil action:nil];
        negativeSpacer.width = 10;
        [self setLeftBarButtonItems:[NSArray arrayWithObjects:negativeSpacer, leftBarButtonItem, nil]];
    } else {
        // Just set the UIBarButtonItem as you would normally
        [self setLeftBarButtonItem:leftBarButtonItem];
    }
}

- (void)addRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem
{
    if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
        // Add a spacer on when running lower than iOS 7.0
        UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc]
                                           initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                                           target:nil action:nil];
        negativeSpacer.width = 10;
        [self setRightBarButtonItems:[NSArray arrayWithObjects:negativeSpacer, rightBarButtonItem, nil]];
    } else {
        // Just set the UIBarButtonItem as you would normally
        [self setRightBarButtonItem:rightBarButtonItem];
    }
}

@end

Y luego, para obtener esto globalmente, tengo una UIViewControllersubclase delgada de la que heredan todos mis controladores de vista.

@interface INFViewController : UIViewController

@end

@implementation INFViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
        [self setupNavBarForPreIOS7Support];
    }
}

- (void)setupNavBarForPreIOS7Support {
    if (self.navigationController) {
        UINavigationItem *navigationItem = self.navigationItem;
        UIBarButtonItem *leftItem = navigationItem.leftBarButtonItem;
        UIBarButtonItem *rightItem = navigationItem.rightBarButtonItem;

        if (leftItem) {
            [navigationItem addLeftBarButtonItem:leftItem];
        }

        if (rightItem) {
            [navigationItem addRightBarButtonItem:rightItem];
        }
    }
}

@end

Me doy cuenta de que estoy comprobando la versión del sistema operativo dos veces (una INFViewControllery otra vez en la categoría), la dejé en la categoría en caso de que quiera usarla como única en cualquier parte del proyecto.

Chris Wagner
fuente
5

para rápido puedes hacer esto

var negativeSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
negativeSpace.width = -17.0
self.navigationItem.rightBarButtonItems = [negativeSpace, requiredButton /* this will be the button which you actually need */]
reza pahlevi
fuente
5
As of iOS 11 wont accept negative space width, in order to align the bar button items to the margin, I have used the below code.

 override func viewWillLayoutSubviews() {
                super.viewWillLayoutSubviews()
                for view in (self.navigationController?.navigationBar.subviews)! {
                    view.layoutMargins = UIEdgeInsets.zero
                }
            }
vinny
fuente
2
este método llamado con retraso
orium
Esta es la solución precisa para hacer esto, el espacio negativo no funcionará desde iOS 11
Rafiqul Hasan
4

Swift 3:

let negativeSpacer:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
        negativeSpacer.width = -10
self.navigationItem.leftBarButtonItems = [negativeSpacer, yourBarButtonItem]
Dvole
fuente
2

Swift 3.1

Para dar espacio negativo al elemento del botón de la barra izquierda:

    let backButton = UIButton.init(type: .custom)
    backButton.frame = CGRect.init(x: 0, y: 0, width: 40, height: 40)
    // negative space
    backButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: -44.0, bottom: 0, right: 0)
    backButton.setImage(Ionicons.iosArrowBack.image(30, color: UIColor(hex: 0xFD6250)), for: .normal)
    backButton.addTarget(self, action: #selector(InviteVC.goBack), for: .touchUpInside)   
    // set back button
    self.navigationItem.leftBarButtonIteUIBarButtonItem.init(customView: backButton) 

rp2701
fuente
1

El espacio negativo no funcionará desde iOS 11

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    // to remove navigation bar extra margin
    for view in (self.navigationController?.navigationBar.subviews)! {
        view.layoutMargins = UIEdgeInsets.zero
    }
}

El código anterior eliminará el margen de ambos lados, leftBarButtonItem y RightBarButtonItem. Si necesita agregar un margen adicional (después de eliminar el margen) agregue el siguiente código

    let rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 17, height: 20))
    rightButton.setImage(UIImage(named: "ic_cart"), for: .normal)

    let rightBarButtomItem = UIBarButtonItem(customView: rightButton)

    let spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: nil, action: nil)
    spacer.width = 28 //This will add extra margin on right side
    navigationItem.rightBarButtonItems = [spacer,rightBarButtomItem]
Rafiqul Hasan
fuente
1
'Error del cliente al intentar cambiar los márgenes de diseño de una vista privada'
Vlad Pulichev
0

Creo que debe usar un botón personalizado con una UIButtonsubclase y, en su subclase, anular -alignmentRectInsets. Olvidé si necesita un valor positivo o negativo para el borde apropiado para que cambie correctamente, pero si uno no funciona, pruebe con el otro.

Zev Eisenberg
fuente
0

trabajó para mi

rightBarButton.customView? .transform = CGAffineTransform (traducciónX: 10, y: 0)

drogadicto
fuente
-1

Buena decisión, muchas gracias! Necesitaba agregar solo dos elementos al lado izquierdo del encabezado de navegación. Esta es mi solución:

  // Settings Button
  // This trick correct spacing between two left buttons
  UIBarButtonItem *settingsButtonItem = [[UIBarButtonItem alloc] init];
  UIView *settingsButtonItemView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 22.0, 22.0)];
  settingsButtonItem.customView = settingsButtonItemView;
  UIButton *settingsButton = [UIButton buttonWithType:UIButtonTypeSystem];
  settingsButton.frame = settingsButtonItemView.frame;
  [settingsButton setImage:[UIImage imageNamed:@"settings"] forState:UIControlStateNormal];
  settingsButton.tintColor = [[[[UIApplication sharedApplication] delegate] window] tintColor];
  [settingsButton addTarget:self action:@selector(showSettings:) forControlEvents:UIControlEventTouchDown];
  [settingsButtonItemView addSubview:settingsButton];

  // Star Button
  UIBarButtonItem *starButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"star_gray"] style:UIBarButtonItemStyleBordered target:self action:@selector(showStarred)];
  starButtonItem.width = 22.0;
  NSLog(@"%f", starButtonItem.width);

  // Negative Spacer
  // It shifts star button to the left
  UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
  negativeSpacer.width = -10.0;

  NSArray *leftNavigtaionBarButtonItems = @[negativeSpacer, starButtonItem, settingsButtonItem];
  [self.navigationItem setLeftBarButtonItems:leftNavigtaionBarButtonItems];
Igor Leonovich
fuente