Come modificare gli spazi vuoti di UIBarButtonItem sinistro e destro in UINavigationBar [iOS 7]


84

Prima stavo usando iOS 6.1, ma ora sono passato a iOS 7. Insieme ad altri problemi, ho notato che nella mia barra di navigazione, lo spazio sinistro dell'elemento del pulsante della barra sinistra e lo spazio vuoto destro dell'elemento della barra dei pulsanti destra sono abbastanza più in IOS 7 che in iOS 6.

Devo sapere che c'è un modo per ridurre gli spazi vuoti degli elementi dei pulsanti della barra sinistra e destra nella barra di navigazione

Grazie in anticipo.



@devxoul, UINavigationItem-Margin ha problemi con iOS14. ho creato un problema per questo, se hai qualche soluzione, ti preghiamo di esaminarlo.
Kuldeep

Risposte:


222

Anch'io stavo affrontando questo problema. Ho anche la sensazione che in iOS 7 ci sia più spazio. E ho capito che questo è di circa 10 punti in più. Di solito utilizzo spazi negativi quando voglio LeftBarItemButtoniniziare dal bordo. Questo può essere utile anche per te.

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];

4
Funziona davvero su iOS 7, dato che lo sto usando nei miei due progetti in questo momento ... c'è una differenza nel sistema di punti quindi devi prenderti cura di questo ...
Adnan Aftab

10
Non funziona se si esegue [NSArray arrayWithObjects: requiredButton, negativeSpacer]. Attenti all'ordine.
Mert Buran

3
Funziona alla grande e nota che per rightBarButtonItems lo spaziatore deve essere il primo elemento dell'array se desideri modificare il margine destro
leonaka

1
@C_X per iPhone 6, il margine -16 non sembra funzionare. -20 sembra giusto .. Qualche idea su come possiamo farlo funzionare bene su tutti i dispositivi iPhone?
Vignesh PT

2
Non funziona per iOS 13! Qualcuno sa come ottenere questo risultato in iOS 13?
niku

23

Sulla base della sua risposta @C_X ho creato una categoria che aggiunge e posiziona l'UIBarButtonItem in base alla versione iOS del dispositivo corrente.

// 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

Nel tuo controller di visualizzazione puoi ora usare [self.navigationItem addLeftBarButtonItem:leftBarButtonItem];e[self.navigationItem addRightBarButtonItem:rightBarButtonItem];

Ho anche provato la creazione di sottoclassi UIButtone l'override, -alignmentRectInsetsma questo mi ha dato problemi con le transizioni tra le visualizzazioni.


10

Per Swift 2.0, questa era la mia soluzione per ottenere il seguente effetto ...

(i valori effettivi potrebbero essere diversi, a seconda della situazione)

inserisci qui la descrizione dell'immagine

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)

AGGIORNAMENTO Swift 2.2:

Per Swift 2.2, il action: Selectormetodo è cambiato e deve essere digitato come segue

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


9

Questa è la mia soluzione per Swift 3.0:

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

6

Per correggere questo bug, è necessario UIButtoncreare una sottoclasse in modo da poter eseguire l'override alignmentRectInsets. Dai miei test, dovrai restituire a UIEdgeInsetscon un offset destro positivo o un offset sinistro positivo, a seconda della posizione del pulsante. Questi numeri non hanno senso per me (almeno uno di loro dovrebbe essere negativo, secondo il buon senso), ma questo è ciò che effettivamente funziona:

- (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 ringraziamento speciale a @zev per aver suggerito di provare a modificare alignmentRectInsets.


Grazie per la risposta. Sebbene sia una buona soluzione ma ho preferito la risposta @C_X perché in questo momento sto cercando di evitare la sottoclasse ..
Salman Zaidi

Questo mi ha causato uno strano spostamento dei pulsanti durante le animazioni in iOS 6, iniziavano nel punto sbagliato e si spostavano per abbinare gli inserti dopo il completamento dell'animazione.
Chris Wagner

Non sarei sorpreso. Il codice sopra è necessario solo per ottenere un layout in stile iOS 6 per build iOS 7.
jaredsinclair

Soluzione rapida, bel lavoro. Tuttavia per iOS 9, è necessario restituire gli inserti non impostarli:
A-Majeed

5

Seguendo l' esempio di smek ho creato una categoria, ma l'ho modificata per fornire la compatibilità con le versioni precedenti piuttosto che con le versioni precedenti. Ho impostato tutto per funzionare come voglio in iOS 7 e poi se l'utente sta eseguendo qualcosa di più basso comincio a pasticciare con le cose.

@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

E poi per ottenerlo a livello globale, ho una sottile UIViewControllersottoclasse da cui ereditano tutti i miei controller di visualizzazione.

@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

Mi rendo conto che sto controllando la versione del sistema operativo due volte (una volta INFViewControllere di nuovo nella categoria), l'ho lasciato nella categoria nel caso in cui volessi usarlo come una tantum in qualsiasi punto del progetto.


5

per swift puoi farlo

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 */]

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
                }
            }

2
questo metodo ha chiamato con ritardo
orium

Questa è la soluzione accurata per farlo, lo spazio negativo non funzionerà da 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]

2

Swift 3.1

Per dare spazio negativo all'elemento del pulsante della barra sinistra:

    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) 


1

Lo spazio vegetariano non funziona da iOS 11

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

Il codice sopra rimuoverà il margine da entrambi i lati leftBarButtonItem e RightBarButtonItem. Se è necessario aggiungere un margine extra (dopo aver rimosso il margine) aggiungere il seguente codice

    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]

1
"Errore del client durante il tentativo di modificare i margini del layout di una visualizzazione privata"
Vlad Pulichev

0

Credo che tu debba usare un pulsante personalizzato con una UIButtonsottoclasse e, nella tua sottoclasse, sovrascrivere -alignmentRectInsets. Dimentico se hai bisogno di un valore positivo o negativo per il bordo appropriato per farlo spostare correttamente, ma se uno non funziona, prova l'altro.


0

ha funzionato per me

rightBarButton.customView? .transform = CGAffineTransform (translationX: 10, y: 0)


-1

Bella decisione, grazie mille! Avevo bisogno di aggiungere solo due elementi sul lato sinistro dell'intestazione di navigazione. Questa è la mia soluzione:

  // 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];
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.