iOS7 excessive navigationbar button padding
Asked Answered
D

6

45

I'm experiencing excessive UIBarButtonItem padding/spacing when using the LeftBarItems and RightBarItems (see image below). The icons used on the UIBarButtonItems do not contain extra padding. So I would like to know what's causing this?

enter image description here

Doorkeeper answered 19/9, 2013 at 14:28 Comment(1)
I see this also. Interested in a solution.Centering
E
27

I use this in order to remove space before the first item.

However it doesn't work between system items like UIBarButtonSystemItemAdd, only with UIBarButtonItem that has an image.

@interface UIBarButtonItem (NegativeSpacer)
+(UIBarButtonItem*)negativeSpacerWithWidth:(NSInteger)width;
@end
@implementation UIBarButtonItem (NegativeSpacer)
+(UIBarButtonItem*)negativeSpacerWithWidth:(NSInteger)width {
    UIBarButtonItem *item = [[UIBarButtonItem alloc]
                             initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                             target:nil
                             action:nil];
    item.width = (width >= 0 ? -width : width);
    return item;
}
@end

Use it like this:


UIBarButtonItem *item0 = [UIBarButtonItem negativeSpacerWithWidth:13];
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"sidebar.png"]
                                                          style:UIBarButtonItemStylePlain
                                                         target:vc
                                                         action:@selector(sideMenuAction:)];
NSArray* items = @[item0, item1];
[vc.navigationItem setLeftBarButtonItems:items animated:NO];
[vc.navigationItem setLeftItemsSupplementBackButton:YES];
Elinorelinore answered 21/9, 2013 at 13:42 Comment(7)
Thanks that's a start. But given that even the facebook app devs had to resort to introduce a new bottom toolbar hosting items that used to reside in the navigation bar, I think this is going to stay.Doorkeeper
Changed name to -negativeSpacerWithWidth: and made it handle negative values correctly.Polaris
This isn't working for me... Has this changed recently (i.e. iOS 7)?Classless
Works for me in iOS 7 on a UIToolbar.Wulf
Works for me on iOS7 UINavigationBar. `[vc.navigationItem setLeftItemsSupplementBackButton:YES];' is not necessary.Couch
But it seem doesnt work with right item, here is how i did with right item:UIBarButtonItem *rightSpacer = [UIBarButtonItem negativeSpacerWithWidth:13];[self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:rightItem,rightSpacer, nil]];Couch
It works with the right. It seems like the spacer should be listed second, but... that's not how it works. If you list the spacer first in the right array it will work.Lindahl
R
23

You can move the image

self.myBarButtonItem.imageInsets = UIEdgeInsetsMake(0, 25, 0, -25);
Revest answered 20/10, 2014 at 15:41 Comment(1)
Unfortunately this does not move the hit area of the button, only its image. But a good solution if you just need to move the button a little bit!Rubyeruch
S
8

Apple silently increased the horizontal spacing constraints for UIBarButtonItems and sadly, still hasn't added any UIAppearance methods to adjust the horizontal positioning of UIBarButtonItems.

The best solution (which worked for me) is to wrap your UIBarButtonItems in a UIView using initWithCustomView: and adjust the bounds of that custom view to get your desired positioning. Here's a good answer on how to do this.

If you want to take things a step further, you can create a category on UIBarButtonItem with class methods that return the bar buttons you use throughout your app. That way, when you a need a bar button, you can call something like:

self.navigationItem.leftBarButtonItem = [UIBarButtonItem mySearchBarButtonItemWithTarget:self selector:@selector(search)];
Sodality answered 20/9, 2013 at 18:59 Comment(0)
J
6

There are two kinds of button on the navigation bar in iOS 7: button with image and button with text. I wrote a class to do it. Here is how:

GlobalUICommon.h:

@interface UIBarButtonItem(CustomUIOfONE)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image highlightedImage:(UIImage*)highlightedImage xOffset:(NSInteger)xOffset target:(id)target action:(SEL)action;

+ (UIBarButtonItem*)barItemWithTitle:(NSString*)title xOffset:(NSInteger)xOffset target:(id)target action:(SEL)action;

@end

GlobalUICommon.m:

@implementation UIBarButtonItem(CustomUIOfONE)

+ (UIBarButtonItem*)barItemWithImage:(UIImage*)image highlightedImage:(UIImage*)highlightedImage xOffset:(NSInteger)xOffset target:(id)target action:(SEL)action
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    [button setImage:image forState:UIControlStateNormal];
    [button setImage:highlightedImage forState:UIControlStateHighlighted];
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        [button setImageEdgeInsets:UIEdgeInsetsMake(0, xOffset, 0, -xOffset)];
    }

    UIBarButtonItem *customUIBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
    return customUIBarButtonItem;
}

+ (UIBarButtonItem*)barItemWithTitle:(NSString*)title xOffset:(NSInteger)xOffset target:(id)target action:(SEL)action
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setTitle:title forState:UIControlStateNormal];
    [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
    [button.titleLabel setFont:[UIFont systemFontOfSize:15]];
    [button setFrame:CGRectMake(0, 0, [button.titleLabel.text sizeWithFont:button.titleLabel.font].width + 3, 24)];
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        [button setContentEdgeInsets:UIEdgeInsetsMake(0, xOffset, 0, -xOffset)];
    }

    UIBarButtonItem *customUIBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
    return customUIBarButtonItem;
}

@end

YourViewController.m:

Example for Button with Image:

UIBarButtonItem* leftButtomItem = [UIBarButtonItem barItemWithImage:[UIImage imageNamed:@"yourImage"]
                                                   highlightedImage:[UIImage imageNamed:@"yourImage"]
                                                            xOffset:-11
                                                             target:self
                                                             action:@selector(yourHandler)];
self.navigationItem.leftBarButtonItem = leftButtomItem;
UIBarButtonItem* rightButtonItem = [UIBarButtonItem barItemWithImage:[UIImage imageNamed:@"yourImage"]
                                                   highlightedImage:[UIImage imageNamed:@"yourImage"]
                                                            xOffset:11
                                                             target:self
                                                             action:@selector(yourHandler)];
self.navigationItem.rightBarButtonItem = rightButtonItem;

Example for Button with Text:

self.navigationItem.leftBarButtonItem = [UIBarButtonItem barItemWithTitle:@"yourText" xOffset:-11 target:self action:@selector(yourHandler:)];
self.navigationItem.rightBarButtonItem = [UIBarButtonItem barItemWithTitle:@"yourText" xOffset:11 target:self action:@selector(yourHandler:)];

That's it.

Jannjanna answered 3/12, 2013 at 0:54 Comment(0)
A
2

I solved this by using storybord interface.

1.Select the Bar item.

2.Select the Size Inspector.

Here you can find image Inset,using top,bottom AND left , right you can change the position of Bar Item.

Abramabramo answered 6/12, 2015 at 10:30 Comment(0)
A
0

As @Luda comments, the solution is to

self.myBarButtonItem.imageInsets = UIEdgeInsetsMake(0, 25, 0, -25);

However, @andrrs also points a problem here when inset is large: the hit area. In this case,we have to implement a way to setHitTestEdgeInsets. Below is an category method:

@implementation UIButton (Extensions)

@dynamic hitTestEdgeInsets;

static const NSString *KEY_HIT_TEST_EDGE_INSETS = @"HitTestEdgeInsets";

-(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets {
    NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)];
    objc_setAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(UIEdgeInsets)hitTestEdgeInsets {
    NSValue *value = objc_getAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS);
    if(value) {
        UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets;
    }else {
        return UIEdgeInsetsZero;
    }
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) ||       !self.enabled || self.hidden) {
        return [super pointInside:point withEvent:event];
    }

    CGRect relativeFrame = self.bounds;
    CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets);

    return CGRectContainsPoint(hitFrame, point);
}

@end
Anvers answered 17/12, 2015 at 15:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.