How to adjust space between two UIBarButtonItem in rightBarButtonItems

47,698

Solution 1

Updated at Jul 2015

A better way to do this is to use storyboard (tested in Xcode 6.4). First, add a UINavigationItem; secondly, add a Bar Button Item; thirdly, add a view to the Bar Button Item you just created in step 2; fourthly, add as many buttons as you wish into that view you just dragged in; lastly, adjust the space with your mouse and constraints.

Related Questions

Can't assign multiple Buttons to UINavigationItem when using Storyboard with iOS 5

How to add buttons to navigation controller visible after segueing?


Old Answer (Only acceptable for small insets)

Use imageInsets property:

leftButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -15);
rightButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, 0);

for three or more buttons, the middle one(s) get both insets:

leftButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -15);
middleButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, -15);
rightButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, 0);

For the right side buttons, be careful: the FIRST button in the item array is the RIGHT one:

rightButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, 0);
middleButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, -15);
leftButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -15);

IMPORTANT: Split the inset between the two neighbors; if apply the entire inset to one edge, it will become obvious that the buttons are overlapping in the "blank" space - one button gets all of the "gap" touches. Even when "split" the adjustment like this, at -40 on both edges, the tap will definitely go to wrong button sometimes. -15 or -20 is the most to consider using with this technique.

By applying this method, the button could even be moved around in four directions.

Solution 2

My solution is using a custom view for right bar buttons. Create a horizontal stackview with equal spacing and add any number of buttons as subview.

Sample code:

func addRightBarButtonItems()
{
    let btnSearch = UIButton.init(type: .custom)
    btnSearch.setImage(UIImage(systemName: "magnifyingglass"), for: .normal)
    btnSearch.addTarget(self, action: #selector(MyPageContainerViewController.searchButtonPressed), for: .touchUpInside)
    
    let btnEdit = UIButton.init(type: .custom)
    btnEdit.setImage(UIImage(systemName: "pencil"), for: .normal)
    btnEdit.addTarget(self, action: #selector(MyPageContainerViewController.editButtonPressed), for: .touchUpInside)
    
    let stackview = UIStackView.init(arrangedSubviews: [btnEdit, btnSearch])
    stackview.distribution = .equalSpacing
    stackview.axis = .horizontal
    stackview.alignment = .center
    stackview.spacing = 8
    
    let rightBarButton = UIBarButtonItem(customView: stackview)
    self.navigationItem.rightBarButtonItem = rightBarButton
}

Solution 3

Swift 5

In your AppDelegate add this code:

let stackViewAppearance = UIStackView.appearance(whenContainedInInstancesOf: [UINavigationBar.self])
stackViewAppearance.spacing = -10

This will work with no additional code in more recent SDK versions as UIBarButtonItems are already contained in a horizontal UIStackView

Solution 4

First:

For UIBarButtonItem you must use constructor init(customView: UIView)

Second:

Use fixedSpace for set space between buttons

example:

let firstButton = UIButton()
let firstButtonItem = UIBarButtonItem(customView: firstButton)

let secondButton = UIButton()
let secondButtonItem = UIBarButtonItem(customView: secondButton)

let space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
space.width = WIDTH

self.navigationItem.rightBarButtonItems = [firstButtonItem, space, secondButtonItem]

Solution 5

One line of code is all you need to decrease the space between buttons in the navigation bar:

UIStackView.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).spacing = -10

You must place this line in your code before you add the buttons to the navigation bar.

Share:
47,698

Related videos on Youtube

Bob
Author by

Bob

Software engineer

Updated on July 09, 2022

Comments

  • Bob
    Bob almost 2 years

    I am using the following codes to add two button to self.navigationItem.rightBarButtonItems, and I think in iOS7, the space between two buttons are too wide, is there a way to decrease the space between these two buttons?

    UIBarButtonItem *saveStyleButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"save.png"] style:UIBarButtonItemStyleBordered target:self action:@selector(saveStyle)];
    
    UIBarButtonItem *shareStyleButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(shareStyle)];
    
    NSArray *arr= [[NSArray alloc] initWithObjects:shareStyleButton,saveStyleButton,nil];
    
    self.navigationItem.rightBarButtonItems=arr;
    

    Appreciate any hint or idea.

  • Bob
    Bob over 10 years
    Tried both, but neither works. It seems that there is a minimal value which couldn't be overwritten.
  • Joride
    Joride over 10 years
    Maybe try wit custom view see how small you can make that custom view to find out if there is a lower limit. I guess that the system ones are just as they are and pretty much immutable (unless you hack something maybe).
  • Bob
    Bob over 10 years
    holy crap, i solve it myself with just one more line of code!
  • Bob
    Bob over 10 years
    The code is saveStyleButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -50);
  • Bob
    Bob over 10 years
    And I think by applying this method the button could be even be moved around in four directions! what a bonus point!
  • tybro0103
    tybro0103 about 10 years
    While this will move the image, it does not move the tap-able area.
  • Aron Lindberg
    Aron Lindberg over 9 years
    To preserve the tap-able area you want to edit the imageInsets on both the left and right UIBarButtonItem like this: firstButton.imageInsets = UIEdgeInsetsMake(0, 0, 0, -25); secondButton.imageInsets = UIEdgeInsetsMake(0, -25, 0, 0);
  • Ramesh
    Ramesh about 9 years
    Tried negative insets, visuals are properly adjusted; but, tap is not accurate. E.g. If you have 3 button and used the imageInsets to make the spacing tighter, the tap on button is not mapped to the actual button.
  • Alphonse R. Dsouza
    Alphonse R. Dsouza over 8 years
    It worked perfectly with Storyboard and UIBarbuttonItem with customView
  • ToolmakerSteve
    ToolmakerSteve over 7 years
    How can you add some space between these buttons?
  • ToolmakerSteve
    ToolmakerSteve over 7 years
    Trying on iOS 10.2: positive values of width work, the neighboring buttons are farther apart, but negative value has same result as zero value: the neighboring buttons are at the same locations as if the FixedSpace spacer was not there. I suspect they have nullified this ability to overlap items.
  • ToolmakerSteve
    ToolmakerSteve over 7 years
    FWIW: the old approach, negativeInsets, are a tolerable hack for small value such as -10, but for larger values you soon discover that the buttons are actually overlapping: one of the buttons is "in front", and gets the tap anywhere in the overlapping area. I mention this because if one only needs a small tweak, setting negativeInset is easy to do in code, so is tempting - just don't adjust too far.
  • ToolmakerSteve
    ToolmakerSteve over 7 years
    @AronLindberg - "splitting" the image-insets between the buttons does help, but be aware that the buttons do still end up with some overlap. This can be seen with a large offset, especially in emulator, where can use a mouse to see exactly where the touch is. The technique seems fine for -10 from each side, but is borderline at -25. At -40, its a definite fail in my tests; with three buttons, the middle one is receiving tap over the entire (small) visual gap - even slightly into the edge of neighbor button's icon. emulator, iOS 10.2, iPhone SE, 44 pixel icons (22@x2).
  • Slobodan Antonijević
    Slobodan Antonijević about 7 years
    The updated part here worked perfectly for me, as I only needed the logo image to display on the right, and not in center as title. And simply disabling the button did the trick. thumbs up @Bob
  • Glenn Posadas
    Glenn Posadas over 5 years
    This is so perfect! Thank you for this. Such a shame that an experienced iOS engr like me struggles with handling back buttons in iOS whenever the project has so multiple custom nav bar designs! Although I had to adjust and test lots of times my implementation using this code for different iOS versions. Thanks again.
  • Rishab
    Rishab over 5 years
    This is a good solution. However, if the title of view controller is too big this spacing is neglected.
  • Micah Montoya
    Micah Montoya about 5 years
    This works for swift 4 if the numbers are positive.
  • Lance Samaria
    Lance Samaria over 4 years
    This worked for me but to bring them really close to each other I set: stackview.spacing = 0
  • Muhammad Danish Qureshi
    Muhammad Danish Qureshi almost 3 years
    Very Good solution...! Thanks...!
  • iOSDude
    iOSDude over 2 years
    @AronLindberg reduce space between 3 buttons. I've 3 right bar buttons I want reduce the default space between them, all 3 created programmatically in Objective C. When I add this values it increases the space between buttons and if i make -15 to -5 it was space as like default space is there any way to reduce space between 3 buttons????. **firstButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, 0); secondButton.imageInsets = UIEdgeInsetsMake(0.0, -15, 0, -15); thirdButton.imageInsets = UIEdgeInsetsMake(0.0, 0.0, 0, -15); **
  • Binaya Thapa Magar
    Binaya Thapa Magar over 2 years
    Hi a newbie here, how do you set the height and width of buttons then?
  • Natalia Terlecka
    Natalia Terlecka about 2 years
    Perfect, worked for me