Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIBarButtonItem with custom view not properly aligned on iOS 7 when used as left or right navigation bar items

The following code works up through iOS 6:

UIButton *myButton = nil;
myButton = [UIButton buttonWithType:UIButtonTypeCustom];
myButton.bounds = CGRectMake(0,0,44,30);
// setup myButton's images, etc.

UIBarButtonItem *item = nil;
item = [[UIBarButtonItem alloc] initWithCustomView:customButton];

This is how the button is supposed to be aligned:

Normal positioning

However, on iOS 7, the button appears to be offset from the right or left by too many pixels:

Incorrect positioning on iOS 7

How can I get my custom bar button items to be aligned properly?

like image 600
jaredsinclair Avatar asked Sep 17 '13 22:09

jaredsinclair


4 Answers

Works until iOS11!

You can use negative flexible spaces and rightBarButtonItems property instead of rightBarButtonItem:

UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spacer.width = -10; // for example shift right bar button to the right

self.navigationItem.rightBarButtonItems = @[spacer, yourBarButton];
like image 196
malex Avatar answered Nov 01 '22 13:11

malex


In order to fix this bug, you must subclass UIButton so that you can override alignmentRectInsets. From my testing, you'll need to return a UIEdgeInsets with either a positive right offset or a positive left offset, depending on the button position. These numbers make no sense to me (at least one of them should be negative, according to common sense), but this is what actually works:

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

Special thanks to @zev for suggesting I try adjusting alignmentRectInsets.

like image 42
jaredsinclair Avatar answered Nov 01 '22 13:11

jaredsinclair


I have tried all of the answers above and nothing worked for me. And here is what works, if anyone would need this:

(No subclassing needed)

// Add your barButtonItem with custom image as the following 
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleBordered target:self action:@selector(categoryButtonPressed)];
// set your custom image
[barButton setImage:categoryImage];
// finally do the magic
barButton.imageInsets = UIEdgeInsetsMake(0.0, -20, 0, 0);

-Take a look at the result.

Notice the space to the left button and from the right button (the right button has the default behavior)

enter image description here

like image 28
Basheer_CAD Avatar answered Nov 01 '22 12:11

Basheer_CAD


Ok, I went the other "direction". I made everything line up properly via Storyboard with iOS 7 (assuming this is how it will continue to work). And then using the describe sub-class approach, I sub-class UIButton with the following implementation.

- (UIEdgeInsets)alignmentRectInsets {
    UIEdgeInsets insets;
    if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
        if ([self isLeftButton]) {
            insets = UIEdgeInsetsMake(0, -10, 0, 0);
        } else {
            insets = UIEdgeInsetsMake(0, 0, 0, -10);
        }
    } else {
        insets = UIEdgeInsetsZero;
    }

    return insets;
}

- (BOOL)isLeftButton {
    return self.frame.origin.x < (self.superview.frame.size.width / 2);
}

So this code only runs if the device is pre-iOS 7.

Thanks for the insight @jaredsinclair!

like image 10
Chris Wagner Avatar answered Nov 01 '22 12:11

Chris Wagner