Change width of a UIBarButtonItem in a UINavigationBar
Asked Answered
A

6

27

I am creating a UIBarButtonItem and adding it to my navigation bar like so:

(void)viewDidLoad { 

   ...

   // Add the refresh button to the navigation bar
   UIButton *refreshButton = [UIButton buttonWithType:UIButtonTypeCustom];
   [refreshButton setFrame:CGRectMake(0,0,30,30)];
   [refreshButton setImage:[UIImage imageNamed:@"G_refresh_icon.png"] forState:UIControlStateNormal];
   [refreshButton addTarget:self action:@selector(refreshData) forControlEvents:UIControlEventTouchUpInside];
   UIBarButtonItem *refreshBarButton = [[[UIBarButtonItem alloc] initWithCustomView:refreshButton] autorelease];
   self.navigationItem.leftBarButtonItem = refreshBarButton;
}

It looks correct when I run, but I can select the bar button item by tapping the navigation bar anywhere from x = 0 to roughly 100. How can I adjust the selectable area to have a width of 30 px?

Amenity answered 11/6, 2012 at 23:51 Comment(3)
I'm afraid I don't think there is a way to adjust the selectable area. A question though, why would you want the width to be 30 px? iOS Human Interface Guideline states that the comfortable minimum size of tappable UI elements is 44 x 44 points. developer.apple.com/library/ios/#documentation/UserExperience/…Hysterical
Hmm, ok thanks for the link to the guidelines. It seems a bit strange that the selectable area is so wide though.Amenity
@AbdSaniAbdJalal can we change the width of barbuttonitem in storyboard?Adjutant
D
13

One approach you might consider is creating a UIBarButtonItem by calling initWithCustomView:. This is not ideal in that you don't get "selected" states out of the box AND you have to composite your bordered background (if want that look) with your button image, but with that you can more directly specify a frame for your toolbar item. If you're using text for your title instead of images you may still need add in a background image as a subview. Anyway, I'm having the same problem right now and this code works for me:

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button-image.png"]];
imageView.frame = CGRectMake(0, 0, 43, 30);

UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:imageView];

self.navigationItem.leftBarButtonItem = barButtonItem;

Right now this is the only way I know of restricting the auto-sizing of the UIBarButtonItems added to the UINavigationController's navigationItem.

Or try Maggie's solution, which is more thorough than mine.

Devastating answered 3/12, 2012 at 22:36 Comment(2)
only worked when I used UIButton as customView, and not UIImageViewPortmanteau
this solution won't work as it does not have button actions at all. Use UIButton instead.Pandemonium
L
37

Since iOS 11, just setting frame for customView and not UIBarButtonItem won't work (like suggested in accepted answer). It seems like adding Autolayout to UIBarButtonItem overrides the set frame. This post gave me the idea:

navigationItem.leftBarButtonItem?.customView = yourCustomButtonView
let desiredWidth = 35.0
let desiredHeight = 35.0

let widthConstraint = NSLayoutConstraint(item: yourCustomButtonView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: desiredWidth)
let heightConstraint = NSLayoutConstraint(item: yourCustomButtonView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: desiredHeight)

yourCustomButtonView.addConstraints([widthConstraint, heightConstraint])

Also note, that it is preferred that you use UIButton as your CustomView as you have to rely on it to trigger the action.

Lupita answered 5/4, 2018 at 15:13 Comment(2)
It was quite surprising to find out that the nav bar uses Auto Layout by default to place items in it, very useful info here.Secede
Thanks! Its important to know that manipulatinng the frame won't do nothing anymoreKiley
D
13

One approach you might consider is creating a UIBarButtonItem by calling initWithCustomView:. This is not ideal in that you don't get "selected" states out of the box AND you have to composite your bordered background (if want that look) with your button image, but with that you can more directly specify a frame for your toolbar item. If you're using text for your title instead of images you may still need add in a background image as a subview. Anyway, I'm having the same problem right now and this code works for me:

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button-image.png"]];
imageView.frame = CGRectMake(0, 0, 43, 30);

UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:imageView];

self.navigationItem.leftBarButtonItem = barButtonItem;

Right now this is the only way I know of restricting the auto-sizing of the UIBarButtonItems added to the UINavigationController's navigationItem.

Or try Maggie's solution, which is more thorough than mine.

Devastating answered 3/12, 2012 at 22:36 Comment(2)
only worked when I used UIButton as customView, and not UIImageViewPortmanteau
this solution won't work as it does not have button actions at all. Use UIButton instead.Pandemonium
B
8

The key thing with this is to realise that you are changing the custom view's width, rather than the UIBarButton itself.

The code is therefore:

CGRect resizedFrame = myBarButtonItem.customView.frame;
resizedFrame.size.width = myNewWidth;
myBarButtonItem.customView.frame = resizedFrame;

You will also need to trigger the layout change:

[myNavigationBar setNeedsLayout];

All this goes without saying that the layout is being done with Auto Sizing and frames. Incursions into navigation bars with Auto Layout yielded no success. See my question Auto Layout with UINavigationBar and UIBarButtonItem.

Sorry just realised that my code is almost identical to @oscartzombie. Not intentional! I'll leave this answer as I think it's worth adding the layout and other points, in addition to explaining without reference to Interface Bulder or images specifically.

Bernardina answered 19/7, 2013 at 13:6 Comment(2)
I was having issues with the size of my custom UIBarButtonItem, the solution was calling [self.navigationController.navigationBar setNeedsLayout]; in my view controller's -(void)viewDidLoad method.Stop
very underrated answer, saves my day thanks @MaxMacLeodStramonium
P
6

You can do it by dropping an image to the bar button item from the interface builder and changing the width of the custom view with this code:

CGRect frame = self.navigationItem.leftBarButtonItem.customView.frame;
frame.size.width = 141;
self.navigationItem.leftBarButtonItem.customView.frame = frame;
Pentagrid answered 11/1, 2013 at 15:27 Comment(1)
When I set the image property of a bar button item in interface builder, my customView is nil.Hightest
B
6

None of those solutions worked for me and I figure out auto-resizing thing overrides dimensions that you wrote in code.

after creating button by UIButton way, write following code block:

[self.navigationItem.rightBarButtonItem.customView.widthAnchor constraintEqualToConstant:mWidth].active = YES;
[self.navigationItem.rightBarButtonItem.customView.heightAnchor constraintEqualToConstant:mHeight].active = YES;
Bionomics answered 13/11, 2018 at 12:16 Comment(0)
P
5

The following approach worked, see code to change width and height of the button and to add action item as well.

UIButton *imageButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 22, 22)];
[imageButton setBackgroundImage:[UIImage imageNamed:@"message_button"] forState:UIControlStateNormal];
[imageButton addTarget:self action:@selector(messageButtonTapped) forControlEvents:UIControlEventAllEvents];
UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:imageButton];
self.navigationItem.leftBarButtonItem = leftBarButtonItem;

Note: The target and action of the UIBarButtonItem does not apply to image view

Pony answered 27/5, 2015 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.