UIBarButtonItem appearance trouble in iOS 7, could this be an Apple bug?

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-03 06:37:16
David H

It does look like an Apple bug, and you should enter a bug on it with bug reporter. That said, I can give you a relatively painless workaround: add this code to your RecipetTableViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.title = @"Recipe Book";

    UIBarButtonItem *it = [[UIBarButtonItem alloc] initWithTitle:self.title style:UIBarButtonItemStylePlain target:nil action:NULL];
    UIImage * btBack_30 = [[UIImage imageNamed:@"btBack_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
    [it setBackButtonBackgroundImage:btBack_30 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
    self.navigationItem.backBarButtonItem = it;
}

EDIT: You can dup this bug if interested, the more bugs referencing it the more likely apple will fix it:

BUG: 15506447

State:OpenProduct:iOS

19-Nov-2013 03:53 PM

Summary: Setting the UIBarButtonItem appearance proxy for the back bar button item does not have any affect until the second appearance of the button.

Steps to Reproduce: In appDelegate, before anything has appeared, add these statements:

UIImage * gradientImage44 = [[UIImage imageNamed:@"navBar_44"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)]; UIImage * gradientImage32 = [[UIImage imageNamed:@"navBar_32"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)]; // Set the background image for all UINavigationBars [[UINavigationBar appearance] setBackgroundImage:gradientImage44 forBarMetrics:UIBarMetricsDefault]; [[UINavigationBar appearance] setBackgroundImage:gradientImage32 forBarMetrics:UIBarMetricsLandscapePhone];

Expected Results: When a viewController is first pushed, its back button has the image in it.

Actual Results: First time it appears, there is no image. Push the view again and its there. Actually it does appear when you click on the button the very first time, but not when the button first appears.

Version: Xcode 5.0.1, iOS 7.0.3

Notes: Adding this in the root view controller of the navigation controller makes it work:

  • (void)viewDidLoad { [super viewDidLoad];

    self.title = @"Recipe Book"; UIBarButtonItem *it = [[UIBarButtonItem alloc] initWithTitle:self.title style:UIBarButtonItemStylePlain target:nil action:NULL]; UIImage * btBack_30 = [[UIImage imageNamed:@"btBack_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)]; [it setBackButtonBackgroundImage:btBack_30 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; self.navigationItem.backBarButtonItem = it; }

Attached demo project shows the problem.

Configuration:

Attachments: 'DynamicsCatalog.zip' was successfully uploaded.

EDIT: I'm happy to say that again, entering bugs in bug reporter, does sometimes work!

I tried to change a few things in your demo project but as you said nothing works. I thought maybe it's because of the UINavigationController subclass but using a standard one has the same behaviour.

Unfortunately, if you really have to display your button, at launch I would silently do the opening-closing behaviour ... sorry for the uggly proposal

You have to handle customizing the back button item differently for iOS7. Under iOS6, the back button was a bordered button that contains the title of the previous screen with a background image that extended under the whole button.

Under iOS7, the Back control is a chevron image plus the title of the previous screen. If you want to use a custom image to replace the default chevron, you also need to create a custom mask image. iOS 7 uses the mask to make the previous screen’s title appear to emerge from—or disappear into—the chevron during navigation transitions.

Because you are doing this in a storyboard, the best place to set the appearance proxies is in your app delegate's init method.

- (instancetype)init
{
    self = [super init];
    if (self)
    {
        //Other UIAppearance proxy calls go here

        // Customizing the Back Bar Buttons
        //ios6 uses whole button background image
        UIImage * btBack_30 = [[UIImage imageNamed:@"btBack_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
        UIImage * btBack_24 = [[UIImage imageNamed:@"btBack_24"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 5)];
        [[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_30 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
        [[UIBarButtonItem appearance] setBackButtonBackgroundImage:btBack_24 forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];

        if ([[UIDevice currentDevice].systemVersion integerValue] >= 7)
        {
            //ios7 needs additional chevron replacement image
            UIImage * chevronReplacement = nil;
            chevronReplacement = [chevronReplacement imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
            UIImage * chevronTransitionMaskReplacement = nil;
            chevronTransitionMaskReplacement = [chevronTransitionMaskReplacement imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
            [[UINavigationBar appearance] setBackIndicatorImage:chevronReplacement];
            [[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:chevronTransitionMaskReplacement];
        }    
    }
    return self;
}

I was able to fix this by doing the back button customization in the viewWillDisappear method of the view that is pushing to the view on which I want the back button. The reason is because it's the previous view that "owns" the back button, not the current view.

-(void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear: animated];
    UIImage * backButtonImage = [[UIImage imageNamed:@"back.png"] 
                      resizableImageWithCapInsets:UIEdgeInsetsMake(6, 15, 6, 7)];

    UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:self.title 
                      style:UIBarButtonItemStylePlain target:nil action:NULL];
    [buttonItem setBackButtonBackgroundImage:backButtonImage forState:UIControlStateNormal
                      barMetrics:UIBarMetricsDefault];
    self.navigationItem.backBarButtonItem = buttonItem;

}

This is not the bug. This is default apple's iOS7 behavior.

With iOS7 appearance you don't need to set the background. Though if you want you can achieve it using custom bar button into custom navigation bar.

Enjoy Programming !!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!