Как редактировать пустые пространства слева и справа UIBarButtonItem в UINavigationBar [iOS 7]

84

Раньше я использовал iOS 6.1, но теперь я перешел на iOS 7. Наряду с другими проблемами я заметил, что на моей панели навигации левое пространство элемента левой панели кнопок и правое пустое пространство элемента правой панели кнопок довольно больше в iOS 7, чем в iOS 6.

Мне нужно знать, есть ли способ уменьшить пустые места в элементах левой и правой кнопок на панели навигации?

Заранее спасибо.

Салман Заиди
источник
2
Попробуйте это: github.com/devxoul/UINavigationItem-Margin
devxoul
@devxoul, UINavigationItem-Margin имеет проблему с iOS14. Я создал проблему для этого, если у вас есть какое-либо решение, пожалуйста, изучите это.
Kuldeep

Ответы:

222

Я тоже столкнулся с этой проблемой. Еще есть ощущение, что в iOS 7 места больше. И я понял, что это примерно на 10 баллов больше. Я обычно использую отрицательные пробелы, когда хочу LeftBarItemButtonначать с края. Это может быть полезно и для вас.

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
Это действительно работает в iOS 7, так как я использую это в своих нескольких проектах прямо сейчас ... есть разница в системе баллов, поэтому вы должны позаботиться об этом ...
Аднан Афтаб
10
Это не сработает, если вы сделаете [NSArray arrayWithObjects: requiredButton, negativeSpacer]. Следите за порядком.
Мерт Буран
3
Отлично работает, и обратите внимание, что для rightBarButtonItems разделитель должен быть первым элементом в массиве, если вы хотите изменить правое поле
леонака
1
@C_X для iPhone 6, маржа -16 не работает. -20 кажется правильным ... Есть идеи, как сделать так, чтобы это работало на всех устройствах iPhone?
Vignesh PT
2
Не работает на iOS 13! Кто-нибудь знает, как этого добиться в iOS 13?
нику
23

Основываясь на его ответе @C_X, я создал категорию, которая добавляет и позиционирует UIBarButtonItem на основе версии iOS текущего устройства.

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

В вашем контроллере представления теперь вы можете использовать [self.navigationItem addLeftBarButtonItem:leftBarButtonItem];и[self.navigationItem addRightBarButtonItem:rightBarButtonItem];

Я также пробовал создавать подклассы UIButtonи переопределять, -alignmentRectInsetsно это доставляло мне проблемы с переходами между представлениями.

смек
источник
10

Для Swift 2.0 это было моим решением, чтобы получить следующий эффект ...

(фактические значения могут отличаться в зависимости от вашей ситуации)

введите описание изображения здесь

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)

ОБНОВЛЕНИЕ Swift 2.2:

Для Swift 2.2 action: Selectorметод изменился и должен быть набран следующим образом

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

Саймон
источник
9

Это мое решение для Swift 3.0:

rightBtn.imageInsets = UIEdgeInsets(top: 0, left: -13.0, bottom: 0, right: 13.0) 
self.navigationItem.rightBarButtonItem = rightBtn
Tuandapen
источник
6

Чтобы исправить эту ошибку, вы должны создать подкласс, UIButtonчтобы можно было переопределить alignmentRectInsets. По результатам моего тестирования вам нужно будет вернуть a UIEdgeInsetsлибо с положительным смещением вправо, либо с положительным смещением влево, в зависимости от положения кнопки. Эти числа не имеют для меня никакого смысла (по крайней мере, одно из них должно быть отрицательным, согласно здравому смыслу), но вот что действительно работает:

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

Особая благодарность @zev за предложение попробовать приспособиться alignmentRectInsets.

Джаредсинклер
источник
Спасибо за ответ. Хотя это хорошее решение, но я предпочел ответ @C_X, потому что сейчас я стараюсь избегать подкласса ..
Салман Заиди,
Это вызвало у меня странное смещение кнопок во время анимации в iOS 6, они начинались не в том месте и сдвигались, чтобы соответствовать вставкам после завершения анимации.
Крис Вагнер
Я бы не удивился. Приведенный выше код нужен только для получения макета в стиле iOS 6 для сборок iOS 7.
jaredsinclair
Быстрое исправление, хорошая работа. Однако для iOS 9 вам нужно вернуть вставки, а не установить их:
A-Majeed
5

Следуя примеру смека, я создал категорию, но изменил ее, чтобы обеспечить обратную совместимость, а не прямую. Я настраиваю все так, как я хочу, в iOS 7, а затем, если пользователь запускает что-то более низкое, я начинаю возиться с вещами.

@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

А затем, чтобы получить это глобально, у меня есть тонкий UIViewControllerподкласс, от которого наследуются все мои контроллеры представления.

@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

Я понимаю, что дважды проверяю версию ОС (один раз INFViewControllerи снова в категории), я оставил ее в категории, если я хочу использовать ее как одноразовую в любом месте проекта.

Крис Вагнер
источник
5

для быстрого вы можете сделать это

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
этот метод вызван с задержкой
orium
Это точное решение для этого, отрицательное пространство не будет работать с iOS 11
Рафикул Хасан
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

Чтобы оставить отрицательное пространство для элемента левой панели:

    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
источник
1

Negetive Space не будет работать с iOS 11

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

Приведенный выше код удалит маржу с обеих сторон leftBarButtonItem и RightBarButtonItem. Если вам нужно добавить дополнительный запас (после удаления поля), добавьте следующий код

    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
«Ошибка клиента при попытке изменить поля макета частного просмотра»
Влад Пуличев
0

Я считаю, что вам нужно использовать настраиваемую кнопку с UIButtonподклассом, а в своем подклассе переопределить -alignmentRectInsets. Я забываю, нужно ли вам положительное или отрицательное значение для соответствующего края, чтобы заставить его правильно сдвигаться, но если одно не работает, попробуйте другое.

Зев Айзенберг
источник
0

работал на меня

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

наркоман
источник
-1

Хорошее решение, спасибо большое! Мне нужно было добавить всего два элемента в левую часть заголовка навигации. Это мое решение:

  // 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];
Игорь Леонович
источник