Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Custom background for UINavigationBar?

Hi,
how to set a custom background image for the whole navigation bar of a navigation controller? I can't find any appropriate API method.
I tried already to mess around with the views of the UINavigationBar to insert my background view - with the result no not-showing buttons and titles :-/
Also subclassing of UINavigationBar with a new drawRect method does not lead to anywhere - there is simply now way to set the navigation bar for a UINavigationController!
Any help would be highly appreciated!
Best regards,
Matthias Huber

MacBook, Mac OS X (10.5.4), iPhone OS 2.0

Posted on Aug 5, 2008 3:05 AM

Reply
27 replies

Jul 7, 2009 2:16 PM in response to dpedley

I wasn't happy having to make each viewcontroller responsible for sending the background to the back in each its viewDidAppear methods, so I tried subclassing UINavigationBar instead. The UINavigationBar class uses the insertSubview:atIndex: method to insert new UIBarButtons etc. So each time this is called, we need to send our background to the back.


@interface MTNavigationBar : UINavigationBar
{
UIImageView *bg;
}
-(void)setBackgroundImage:(UIImage*)image;
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
@end
@implementation MTNavigationBar
-(void)setBackgroundImage:(UIImage*)image {
if(image == nil) return;
bg = [[UIImageView alloc]initWithImage:image];
bg.frame = CGRectMake(0.f, 0.f, self.frame.size.width, self.frame.size.height);
[self addSubview:bg];
[self sendSubviewToBack:bg];
[bg release];
}
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index
{
[super insertSubview:view atIndex:index];
[self sendSubviewToBack:bg];
}
@end


Now, in my XIB file, I changed the class of the Navigation Bar to MTNavigationBar.
Since the UINavigationController class is still expecting a UINavigationBar in the navigationBar property, I needed to cast it explicitly whenever setting the background. E.g.:

[((MTNavigationBar*) navigationController.navigationBar) setBackgroundImage:[UIImage imageNamed:@"Header.png"]];

Oct 27, 2009 8:54 AM in response to Collin Allen

This works, but has a few flaws:

1) Do NOT override existing methods in categories. This is what subclasses were invented for.

2) In drawing an image that can be repeated (like a gradient), use -drawAsPatternInRect: That way the iPhone does not have to scale but to repeat the image, which is faster.

3) When drawing inside a View, never ever refer to its frame, use its bounds! What you do here will only work in views whose origin is 0,0.

Nov 15, 2009 2:30 PM in response to hubermat

Try overriding - (void)drawRect:(CGRect)rect like so:

@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: @"NavigationBar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end



This works well for me, and doesn't appear to have issues with pushing new view controllers, hidden titles and bar button items, etc. I'm still fairly new at this, though 🙂

Hi,
Nice and quick tip..
I did this as well, it works nice as replacing the navbar image, but it covers the buttonItem (back button for example) when i push a new view controller in my navcontroller... the button is still here cause i can press it, but it is under the image... how can I have the button appear / or having the image as background only??

Dec 21, 2009 3:03 AM in response to Collin Allen

This works perfectly, however if you invoke a MPMoviePlayerController the image is also displayed at the top of the movie player. Apple then reject the application:

"3.3.1 Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs."

There is no documentation for the organization, layout, or subviews of the view hierarchy managed by MPMoviePlayerController in iPhone OS 3.1.2

.. have you an idea how I may prevent this happening?

Jan 10, 2010 1:43 PM in response to hxela

hxela wrote:
"3.3.1 Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs."

There is no documentation for the organization, layout, or subviews of the view hierarchy managed by MPMoviePlayerController in iPhone OS 3.1.2

.. have you an idea how I may prevent this happening?




I ran into this issue with my app, and after a bit of trail and error, the obvious jumped out at me. Although I'm not sure if this is considered using a private api.


@implementation UINavigationBar (UINavigationBarCategory)
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
if([self isMemberOfClass: [UINavigationBar class]]){
UIImage *image = [UIImage imageNamed:@"navBarBackground.png"];
CGContextClip(ctx);
CGContextTranslateCTM(ctx, 0, image.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextDrawImage(ctx, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage);
}else{
[super drawLayer:layer inContext:ctx];
}
}
@end


Based on what I found on this Q&A in regard to overriding drawLayer... I assume this should be safe:
http://developer.apple.com/iphone/library/qa/qa2009/qa1637.html

Feb 15, 2010 2:16 PM in response to Collin Allen

Collin Allen wrote:
Try overriding - (void)drawRect:(CGRect)rect like so:

@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: @"NavigationBar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end


This works well for me, and doesn't appear to have issues with pushing new view controllers, hidden titles and bar button items, etc. I'm still fairly new at this, though 🙂


Thanks a lot!!!
Works for me....

Message was edited by: iSens

Custom background for UINavigationBar?

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.