UINavigationBar setBackgroundImage: forBarMetrics: Not Working

I just switched over to iOS 5 and everything appears to be working in my application aside from the custom navigation bar. I looked around and followed everybody’s suggestion of calling the new methods setBackgroundImage: forBarMetrics: however it doesn’t appear to work. This is the code I’ve tried to place both within the app delegate and within the viewDidLoad method of some of the view controllers:

UINavigationBar *nb = [[UINavigationBar alloc]init];
if( [nb respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)] )
    UIImage *image = [UIImage imageNamed:@"navBarBackground.png"];
    [nb setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
[nb release];

Unfortunately this doesn’t work. If anybody has any suggestions at all, I’m all ears!

  • How can I detect which annotation was selected in MapView
  • UIRefreshControl Stuck After Switching Tabs in UITabBarController
  • Swift 3: URLSession / URLRequest Not Working
  • Why do I get memory warnings with only 7 MB of memory allocated?
  • What does this gdb output mean?
  • Fastest way to get array of NSRange objects for all uppercase letters in an NSString?
  • 6 Solutions Collect From Internet About “UINavigationBar setBackgroundImage: forBarMetrics: Not Working”

    To apply image to all your navigation bars, use the appearance proxy:

    [[UINavigationBar appearance] setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];

    For an individual bar:

    // Assuming "self" is a view controller pushed on to a UINavigationController stack
    [self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];

    In your example, the background image won’t change because nb isn’t hooked up to anything.

    Answer by rob is correct but if application runs on iOS 4.3 or lower app will crash. So you can implement this like

    if([[UINavigationBar class] respondsToSelector:@selector(appearance)]) //iOS >=5.0
        [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"navigationBar.png"] forBarMetrics:UIBarMetricsDefault];
        [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"navBar-Landscape.png"] forBarMetrics:UIBarMetricsLandscapePhone];   

    This will set image for both mode Landscape and Portrait

    You need to get the navigation bar from a navigation controller. Right now you are just creating one and then it deallocs when you release it. You need to get the navigation controller for your view controller.

    UINavigationController * navigationController = [self navigationController];
    UINavigationBar * nb = [navigationController navigationBar];

    Note that if you want to apply the same to a toolbar, it is slightly different. Here’s an example, building on Rob’s answer:

        [[UIToolbar appearance] setBackgroundImage:[UIImage imageNamed:@"NavBarDarkWoodGrain.png"] forToolbarPosition:UIToolbarPositionBottom barMetrics:UIBarMetricsDefault];

    You didn’t do something like use a UINavigationBar subclass? If you do this and override drawRect: on iOS5 and above, things will break.

    See my answer here for a way to support both OS versions.

    This worked for me.

    UIView *parentViewLeft = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
    parentViewLeft.backgroundColor = [UIColor clearColor];
    if ([self.navigationController.navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]) {
        [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"navbar.png"]
    } else {
        UIImageView* imgBG = [[UIImageView alloc]init];
        imgBG.image = [UIImage imageNamed:@"navbar.png"];
        imgBG.frame = CGRectMake(-10,0, 330, 44);
        [parentViewLeft addSubview:imgBG];
    UIBarButtonItem *customBarButtomLeft = [[UIBarButtonItem alloc] initWithCustomView:parentViewLeft];
    self.navigationItem.leftBarButtonItem = customBarButtomLeft;