Jak edytować puste spacje lewego i prawego elementu UIBarButtonItem w UINavigationBar [iOS 7]

84

Wcześniej korzystałem z iOS 6.1, ale teraz przeniosłem się na iOS 7. Wraz z innymi problemami zauważyłem, że na moim pasku nawigacyjnym lewa przestrzeń przycisku lewego paska i prawe puste miejsce elementu prawego paska są dość więcej w IOS 7 niż w iOS 6.

Muszę wiedzieć, czy istnieje sposób, aby zmniejszyć puste przestrzenie elementów przycisków lewego i prawego paska na pasku nawigacyjnym?

Z góry dziękuję.

Salman Zaidi
źródło
@devxoul, UINavigationItem-Margin ma problem z iOS14. Stworzyłem dla tego problem, jeśli masz jakieś rozwiązanie, spójrz na to.
Kuldeep

Odpowiedzi:

222

Ja też miałem ten problem. Mam też przeczucie, że w iOS 7 jest więcej miejsca. I doszedłem do wniosku, że to około 10 punktów więcej. Zwykle używam ujemnych spacji, gdy chcę LeftBarItemButtonzacząć od krawędzi. Może to być również przydatne dla Ciebie.

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
źródło
4
To naprawdę działa w iOS 7, ponieważ używam tego w moich kilku projektach w tej chwili ... jest różnica w systemie punktowym, więc musisz się tym zająć ....
Adnan Aftab
10
Nie działa, jeśli wykonasz [NSArray arrayWithObjects: requiredButton, negativeSpacer]. Uważaj na rozkaz.
Mert Buran
3
Działa świetnie i zwróć uwagę, że dla rightBarButtonItems odstępnik musi być pierwszym elementem w tablicy, jeśli chcesz zmienić prawy margines
leonaka
1
@C_X dla iPhone'a 6, margines -16 wydaje się nie działać. -20 wydaje się mieć rację .. Masz jakiś pomysł, jak sprawić, by to działało dobrze na wszystkich urządzeniach iPhone?
Vignesh PT
1
@TheRohanSanap - dodatnią szerokością byłby odstępnik, który zwiększa ilość pustego miejsca przed pierwszym elementem wizualnym. Ta sztuczka o ujemnej szerokości zmniejsza pustą przestrzeń.
ToolmakerSteve
23

Na podstawie odpowiedzi @C_X stworzyłem kategorię, która dodaje i pozycjonuje UIBarButtonItem w oparciu o wersję iOS obecnego urządzenia.

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

W kontrolerze widoku możesz teraz używać [self.navigationItem addLeftBarButtonItem:leftBarButtonItem];i[self.navigationItem addRightBarButtonItem:rightBarButtonItem];

Próbowałem też tworzyć podklasy UIButtoni zastępować, -alignmentRectInsetsale to powodowało problemy z przejściami między widokami.

smek
źródło
10

W przypadku Swift 2.0 to było moje rozwiązanie, aby uzyskać następujący efekt ...

(rzeczywiste wartości mogą się różnić w zależności od sytuacji)

wprowadź opis obrazu tutaj

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)

AKTUALIZACJA SWIFT 2.2:

W przypadku Swift 2.2 action: Selectormetoda uległa zmianie i należy ją wpisać w następujący sposób

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

Szymon
źródło
9

To jest moje rozwiązanie dla Swift 3.0:

rightBtn.imageInsets = UIEdgeInsets(top: 0, left: -13.0, bottom: 0, right: 13.0) 
self.navigationItem.rightBarButtonItem = rightBtn
tuandapen
źródło
6

Aby naprawić ten błąd, UIButtonmusisz utworzyć podklasę , aby móc nadpisać alignmentRectInsets. Z moich testów będziesz musiał zwrócić a UIEdgeInsetsz dodatnim przesunięciem w prawo lub dodatnim przesunięciem w lewo, w zależności od pozycji przycisku. Te liczby nie mają dla mnie sensu (przynajmniej jedna z nich powinna być ujemna, zgodnie ze zdrowym rozsądkiem), ale tak naprawdę działa:

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

Specjalne podziękowania dla @zev za sugestię, żebym spróbował dostosować alignmentRectInsets.

jaredsinclair
źródło
Dziękuję za odpowiedź. Chociaż jest to dobre rozwiązanie, ale wolałem odpowiedź @C_X, ponieważ w tej chwili staram się uniknąć podklas ...
Salman Zaidi
To spowodowało dziwne przesunięcie przycisków podczas animacji w iOS 6, zaczynały się w niewłaściwym miejscu i przesuwały się, aby dopasować wstawki po zakończeniu animacji.
Chris Wagner,
Nie zdziwiłbym się. Powyższy kod jest potrzebny tylko do uzyskania układu w stylu iOS 6 dla kompilacji iOS 7.
jaredsinclair
Szybka naprawa, niezła robota. Jednak w przypadku iOS 9 musisz zwrócić wstawki, a nie ustawić ich:
A-Majeed
5

Idąc za przykładem Smeka stworzyłem kategorię, ale zmodyfikowałem ją, aby zapewnić kompatybilność wsteczną, a nie do przodu. Skonfigurowałem wszystko, aby działało tak, jak chcę, w iOS 7, a potem, jeśli użytkownik ma coś niższego, zaczynam grzebać w rzeczach.

@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

Aby uzyskać to globalnie, mam cienką UIViewControllerpodklasę, z której dziedziczą wszystkie moje kontrolery widoku.

@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

Zdaję sobie sprawę, że dwukrotnie sprawdzam wersję systemu operacyjnego (raz INFViewControlleri jeszcze raz w kategorii), zostawiłem ją w kategorii na wypadek, gdybyś chciał użyć tego jednorazowo w dowolnym miejscu projektu.

Chris Wagner
źródło
5

szybko możesz to zrobić

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
źródło
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
                }
            }
winny
źródło
2
ta metoda wywołana z opóźnieniem
orium
Jest to dokładne rozwiązanie to zrobić, negatywna przestrzeń nie będzie działać z systemem 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
źródło
2

Swift 3.1

Aby nadać elementowi przycisku lewego paska ujemną spację:

    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
źródło
1

Przestrzeń wegetatywna nie będzie działać z iOS 11

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

Powyższy kod usunie marginesy z obu stron leftBarButtonItem i RightBarButtonItem. Jeśli potrzebujesz dodać dodatkowy margines (po usunięciu marginesu) dodaj następujący kod

    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
źródło
1
„Błąd klienta przy próbie zmiany marginesów układu widoku prywatnego”
Vlad Pulichev,
0

Uważam, że musisz użyć niestandardowego przycisku z UIButtonpodklasą, a w swojej podklasie nadpisać -alignmentRectInsets. Zapominam, czy potrzebujesz wartości dodatniej, czy ujemnej, aby odpowiednia krawędź działała poprawnie, ale jeśli jedna nie działa, spróbuj drugiej.

Zev Eisenberg
źródło
0

pracował dla mnie

rightBarButton.customView? .transform = CGAffineTransform (tłumaczenie X: 10, y: 0)

niezdarny
źródło
-1

Dobra decyzja, wielkie dzięki! Musiałem dodać tylko dwa elementy po lewej stronie nagłówka nawigacji. To jest moje rozwiązanie:

  // 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
źródło