UINavigationBar with solid color or image background

How about a nice navigation bar without default iPhone gradient or with a beautiful background image? Lets do it! The thing we’re going to do in both sub-solutions is to override UINavigationBar drawRect function with a help of category. As you may or may not know categories helps us to add additional functionality to an existing classes even if we can’t access their source directly. For more information read Extending Classes in Objective-C With Categories.

UINavigationBar category

First, as I mentioned before, lets override drawRect method with our own. I usually drop this code at the bottom of my application delegate, but you may want to be more organized than that.

@implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
}
@end

At this point if you run your application (just don’t forget to actually have UINavigationController with visible navigation bar in it) navigation bar will look like.. em.. black rectangle. It means we successfully taken over the control of it’s drawing method and can move further.

Solid color background

So I’ve heard you hate gradients? Since, we’ve already have UINavigationBar in our hands, we can draw a rectangle over it. A nice gray rectangle! Enough of gray already? Okay, red rectangle it will be..

- (void)drawRect:(CGRect)rect {
UIColor *color = [UIColor redColor];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColor(context, CGColorGetComponents( [color CGColor]));
CGContextFillRect(context, rect);
}

And just look at our results! Amazing!

But aren’t we forgetting something? We’re not done here yet. Remember that iPhone uses UINavigationBar property tintColor to style buttons in navigation bar, so unless we want blue buttons in red background (just think about poor eyes of your application users!) we need to alter our code a little bit.

- (void)drawRect:(CGRect)rect {
	UIColor *color = [UIColor redColor];
	CGContextRef context = UIGraphicsGetCurrentContext();
	CGContextSetFillColor(context, CGColorGetComponents( [color CGColor]));
	CGContextFillRect(context, rect);
	self.tintColor = color;
}

Background image

Using image for UINavigationBar background is even more simple! In this example I’ll use 320×44 custom image which also displays my drawing skills.

- (void)drawRect:(CGRect)rect {
	UIColor *color = [UIColor blackColor];
	UIImage *img	= [UIImage imageNamed: @"nav.png"];
	[img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
	self.tintColor = color;
}

Some important things to have in mind: decide what color of buttons suits your background best, keep in mind iPhone dimensions while drawing your background image and don’t forget about landscape mode if your application is going to support it.

12 responses

  1. Posted February 12, 2010 at 10:13 | Permalink

    Hi
    Thanks for that beautiful article. it just solved one of my issues :) .. do you know if there is a way to remove the glossy effect of the buttons as well?
    cheers

    sam

  2. Bobo
    Posted February 22, 2010 at 19:56 | Permalink

    Hi

    Thank you for the great article. I have few viewcontrollers and I want navigation bar to have different color on each controller. How to accomplish this.

    Thank you

    • Foobar Pig
      Posted February 22, 2010 at 23:34 | Permalink

      Okay, I think it’s actually possible. Use drawRect code above to “paint” your UINavigationBar, but use some kind of global color variable or class, so you’ll be able to set/get it, and then, in ViewDidAppear methods of your navigation controllers, set that color to whatever you like and “refresh” your navigation bar like this:

      UINavigationBar *bar = [self.navigationController navigationBar];
      [bar setNeedsDisplay];

      *setNeedsDisplay will initiate redrawing of your navigation bar (drawRect will be called again)

      It should work. Good luck!

  3. Erik
    Posted May 20, 2010 at 04:35 | Permalink

    Great article. I have the need to draw a background image or set a tint color on a navigation bar, but I also need to support doing neither. If my app does not have a background image, what can I do instead to ensure the drawRect method does it normally would do?

    I.E. -

    @implementation UINavigationBar (UINavigationBarCategory)
    - (void)drawRect:(CGRect)rect {
    if(hasImage){
    UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://myimageurl.com/img.jpg"]]];
    [img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    }else{
    ??????
    }
    }
    @end

  4. Ayaz
    Posted June 2, 2010 at 08:29 | Permalink

    Hi,
    Excellent article you finally taught me how to use drawrect method. Can u explain why you used UINavigationBarCategory in the implemenation line or point me to documentation that explains how to do that for other UIcontrols also.
    I am creating theme for my app that is xml based and will be stored in a themes folder of my app. i need to traverse that file and apply theme that does exaclty same i.e set navigation bar styles, tabbar styles etc. What might be best possible solution for doing this? i have got about 7-8 viewcontrollers that needs to be applied that theme on app launch or viewdidload method. Any suggestion would be great.

  5. paula
    Posted June 8, 2010 at 12:59 | Permalink

    Hi,
    Thanks for the post, the information was very useful.
    best regards.

  6. Posted July 14, 2010 at 11:31 | Permalink

    Hey wow, thanks for this!
    If you leave the drawRect method empty and have transparency on for the NavigationBar you can have an invisible navigation bar but the buttons still show up when moving around. Which is just what I needed!! (Since if you just try setting alpha to 0, the buttons disappear as well).

    much appreciated.

Leave a Reply