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 readExtending 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.
1
2
3
4
|
@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..
1
2
3
4
5
6
|
- (
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.
1
2
3
4
5
6
7
|
- (
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.
1
2
3
4
5
6
|
- (
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.
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
I think UIButtonType is what you need:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIButton_Class/UIButton/UIButton.html#//apple_ref/doc/c_ref/UIButtonType
Hope it helps
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
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!
Hi,
I was using the same approach in the iOS 4.3.3 version and it was working fine. But when I upgrade my machine on the iOS 5, then this method stop working. I tried to called the setNeedsDisplay method for the navigationBar but nothing happened and drawRect method did not called. Please suggest me the way to accomplish this feature in iOS 5.
Thanks in advance
Ran into the same problem, I surmise they broke some stuff with os5, but they’ve also added framework support for changing the image:
- (void)setBackgroundImage:(UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics
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
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.
Hi,
Thanks for the post, the information was very useful.
best regards.
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.
Even though this works with categories, it’s highly unadvisable to use them. You should rather use subclasses.
Taken from the Apple Objective C Reference Library:
“Although the language currently allows you to use a category to override methods the class inherits, or even methods declared in the class interface, you are strongly discouraged from using this functionality. A category is not a substitute for a subclass.”
See:http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/articles/occategories.html
So how would you do this with subclassing? Would it work to subclass the NavBar and from your subclass change the colors?
Foobars approach is really quite simple.
Subclassing uses pretty much the same approach, you create a subclass of UINavigationBar and define your own drawRect, that’s it. This way, you have a) code that doesn’t violate the programming guidelines and b) preserved the possibility to access drawRect of the superclass which might come in handy, in case apple changes this class.
@implementation UINavigationControllerEx
-(id) init{
if(self=[super init]){
UINavigationBarEx *navigationBarEx = [[UINavigationBarEx alloc] init];
self.navigationBar = newNavagitionBar;
}
return self;
}
I cannot do this,
navigationBar is readOnly property,
then how to achieve this by using SubClass?
The reason for not doing this in a category is that you may not be the only category declared on that class. If someone else’s code, say a library, does the same thing it becomes undefined and you no longer know who’s code will be called.
The old school way of doing this is to use class_replaceMethod, (#import ) but of course your code could be replaced just as easily. Also it is not clear to me whether or not your App will get rejected for using that call. Until Apple provides an easy method for subclassing the navigation bar, categories will have to suffice.
That was an #import of objc/runtime.h which got stripped because of the gt and lt.
Gday, This approach is actually cool
You rock!
thanks a lot man, you just saved (part) of my life
Hi, nice work. But do you know how to do the opposite? I want to tint my UIButtons like those UIBarButtonItems on UINavigationBar.
Thank you for this great tutorial!
Just want to ask, how to subscribe via iphone? Cause I always outdoor all the time. Your blog is a source of decent materials, I really like read it when I waiting for something.
Very valuable info…helped a lot…thanks a ton.
Thank you alot.
Your Solution’s very helpful.
Only 10 minutes I can custom my bar by your way.
Thank for sharing
Thanks so much for giving me an update on this subject matter on your website. Please realise that if a fresh post appears or in case any modifications occur about the current submission, I would be considering reading more and finding out how to make good utilization of those approaches you reveal. Thanks for your time and consideration of people by making this blog available. Phone Cards
Even marriage can be handled with concerted attempt and dedication, such a lot marriages have turn into a significant issue, please spend some time boring. Whilst bearing in mind the issue of marriage, it’s simply ahead of taking any motion.
I just couldn’t depart your website before suggesting that I really enjoyed the standard info a person provide for your visitors? Is gonna be back often in order to check up on new posts
Outstanding – I should really certainly pronounce, impressed with your site. I had no difficulty navigating by means of all the tabs also as linked info ended up being really simple to perform to entry. I lately discovered what I hoped for just before you realize it whatsoever.
I got what you intend, saved to fav, very nice site.
me gusta muchisimo tu pagina
Thanks. That was helpful, although I created a subclass of UINavigationBar instead of creating a category.
59. Thank you for another informative site. Where else could I get that type of info written in such a perfect way? I’ve a project that I am just now working on, and I’ve been on the look out for such information.
Would you mind basically pages and use a number of your posts so long as I provide credit and sources to your internet site? My blog site is incorporated in the identical area of interest as yours and my visitors would genuinely reap the benefits of most of the information you provide here. Please inform me if the alright with you. Thanks a whole lot!
It’s exhausting to find educated folks on this matter, however you sound like you understand what you’re speaking about! Thanks
Hello my family member! I want to say that this article is awesome, nice written and come with almost all vital infos. I¡¦d like to peer extra posts like this .
Hello,
Amazing but….
We also want tutorial to change label color, We want it black
Hmm. I have been successfully doing something like this, but it doesn’t appear to work in iOS 5. Any suggestions?
Looks like it only works in iOS 5 if you subclass the UINavigationBar, not if you employ a category on UINavigationBar itself.
Oh, what a surprise, my predictions from my previous post where correct. As I said, the category-method is faulty anyway, the usage of subclasses, as Ron suggests, is your best bet.
Anyone know how to do this for a UIToolbar?
Subclassing does not work easily because, as someone mentioned, the navigationBar property is read-only. One workaround to this problem is to create the nav bar in your xib file instead of programmatically. You can change the class type there.
That is a beneficial mindset, however isn’t produce virtually any sence whatsoever talking about of which mather. Just about any approach thank you and i had try to talk about a person’s publish straight into delicius but it surely is apparently a dilemma with all your blogging is it possible to make sure you recheck them. with thanks just as before.
AGpTIUGl Cheap
Here is an alternative solution that lets you use your own custom subclass of UINavigationBar:
https://gist.github.com/1253807
this doesn’t work!
and I’m not sure it’s Appstore safe.
I use the category method myself, but as others have pointed out this is not supported in iOS 5.
Now discussing iOS 5 outside of apples approved forums is against the developers license, however those with access to the iOS 5 docs I strongly suggest you have a look at the UINavigationBar reference. You might find something that will make this a lot easier.
On iOS 4.3 & simulator 4.3, this causes the navbar to become transparent, discussed here:
http://stackoverflow.com/questions/6783061/disappearing-navigationbar-color-in-ios-4-3