UIBarButtonItem with custom view not properly alig

2019-01-08 03:20发布

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?

15条回答
Rolldiameter
2楼-- · 2019-01-08 03:55

Change the following for your UIButton

Control -> Alignment -> Horizontal to Align Right

查看更多
何必那么认真
3楼-- · 2019-01-08 03:58

Not a huge fan of subclassing UIButton or method swizzling from Marius's answer: https://stackoverflow.com/a/19317105/287403

I just used a simple wrapper, and moved the button's frame's x in a negative direction until I found the correct positioning. Button tapping appears to be fine as well (although you could extend the width of the button to match the negative offset if you needed).

Here's the code I use to generate a new back button:

- (UIBarButtonItem *) newBackButton {
    // a macro for the weak strong dance
    @weakify(self);
    UIButton *backButton = [[UIButton alloc] init];
    [backButton setTitle:@"Back" forState:UIControlStateNormal];
    backButton.titleLabel.font = [UIFont systemFontOfSize:17];
    CGFloat width = [@"Back" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:17]} context:nil].size.width + 27;
    backButton.frame = CGRectMake(-17.5, 0, width + 17.5, 44);
    [backButton setImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] forState:UIControlStateNormal];
    [backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 14, 0, 0)];
    [backButton setTitleColor:mTCOrangeColor forState:UIControlStateNormal];
    backButton.contentEdgeInsets = UIEdgeInsetsZero;
    backButton.imageEdgeInsets = UIEdgeInsetsZero;
    [backButton addEventHandler:^(id sender) {
        // a macro for the weak strong dance
        @strongify(self);
        // do stuff here
    } forControlEvents:UIControlEventTouchUpInside];
    UIView *buttonWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 44)];
    [buttonWrapper addSubview:backButton];
    return [[UIBarButtonItem alloc] initWithCustomView:buttonWrapper];
}
查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-08 04:03

Tested in iOS 11

 public lazy var navigationBackBarButton : UIBarButtonItem = {

        let backBarButtonIcon = <Image Literal here>
        let backBarButton = UIBarButtonItem(image: backBarButtonIcon, style: .plain, target: self, action: #selector(self.backBarButtonTouched(_:)))
        backBarButton.imageInsets = UIEdgeInsets(top: 0.0, left: -9.0, bottom: 0.0, right: 0.0)
        return backBarButton

    }()
查看更多
成全新的幸福
5楼-- · 2019-01-08 04:05

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

查看更多
太酷不给撩
6楼-- · 2019-01-08 04:06

I would like to add to @jaredsinclair confirmed answer the below override methods to those who have text and/or image in their navigation button, otherwise the text and the image won't be aligned (only the background image):

- (UIEdgeInsets) titleEdgeInsets {
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
    if (IF_ITS_A_LEFT_BUTTON) {
    {
        return UIEdgeInsetsMake(0, 0, 0, 9.0f);
    }
    else
    { // IF_ITS_A_RIGHT_BUTTON
        return UIEdgeInsetsMake(0, 9.0f, 0, 0);
    }
}
return [super titleEdgeInsets];
}

- (UIEdgeInsets)imageEdgeInsets {
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
    if (IF_ITS_A_LEFT_BUTTON)
    {
        return UIEdgeInsetsMake(0, 0, 0, 9.0f);
    }
    else
    { // IF_ITS_A_RIGHT_BUTTON
        return UIEdgeInsetsMake(0, 9.0f, 0, 0);
    }
}

return [super imageEdgeInsets];
}

p.s. the macro is:

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
查看更多
别忘想泡老子
7楼-- · 2019-01-08 04:08

A better solution without jumping buttons arround can be found here:

Custom UIBarButtonItem alignment off with iOS7

查看更多
登录 后发表回答