10

I am having problems with properly displaying background image of navigation view. Here is the pic:

alt text

Here is the code:

- (id)initWithStyle:(UITableViewStyle)style {
    if (self = [super initWithStyle:style]) {

        UIImage *image = [UIImage imageNamed: @"bg_table_active.png"];
        UIImageView *imageview = [[UIImageView alloc] initWithImage: image];
        UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
                                       initWithTitle:NSLocalizedString(@"Settings", @"")
                                       style:UIBarButtonItemStyleDone
                                       target:self
                                       action:@selector(GoToSettings)];
        self.navigationItem.titleView = imageview;
        self.navigationItem.rightBarButtonItem = addButton;
        self.navigationItem.hidesBackButton = TRUE;
    }
    return self;
}

How can I make the picture stretch to the whole navigation view?

Community
  • 1
  • 1
Mladen
  • 25,578
  • 11
  • 39
  • 48

8 Answers8

24

I do exactly this in my app. Within AppDelegate I have this code:

@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect
{
  UIImage *image = [UIImage imageNamed: @"custom_nav_bar.png"];
  [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end
Mike Rundle
  • 486
  • 4
  • 9
  • 2
    It is important to ensure the opacity of the *background* of the navigation bar is 0% – Casebash Jan 12 '10 at 01:31
  • I see solutions like this all over the place, but I cannot seem to get it to call my custom `drawRect` code. Could I be doing something wrong? – Dan F Nov 09 '11 at 21:47
  • 2
    @DanF UINavigationBar's drawRect will not be called on iOS 5.0. – Ajith Dec 28 '11 at 08:04
9

I modified Mike Rundle's version so that the a custom image can be set if necessary. I also merged in 40lb-suit-of-bees suggested changes. initImageDictionary needs to be called during initialisation:

//UINavigationBar+CustomImage.h
#import <Foundation/Foundation.h>

@interface UINavigationBar(CustomImage)
+ (void) initImageDictionary;
- (void) drawRect:(CGRect)rect;
- (void) setImage:(UIImage*)image;
@end


//UINavigationBar+CustomImage.m    
#import "UINavigationBar+CustomImage.h"
//Global dictionary for recording background image
static NSMutableDictionary *navigationBarImages = NULL;

@implementation UINavigationBar(CustomImage)
//Overrider to draw a custom image

+ (void)initImageDictionary
{
    if(navigationBarImages==NULL){
        navigationBarImages=[[NSMutableDictionary alloc] init];
    }   
}

- (void)drawRect:(CGRect)rect
{
    NSString *imageName=[navigationBarImages objectForKey:[NSValue valueWithNonretainedObject: self]];
    if (imageName==nil) {
        imageName=@"header_bg.png";
    }
    UIImage *image = [UIImage imageNamed: imageName];
    [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}

//Allow the setting of an image for the navigation bar
- (void)setImage:(UIImage*)image
{
    [navigationBarImages setObject:image forKey:[NSValue valueWithNonretainedObject: self]];
}
@end
Community
  • 1
  • 1
Casebash
  • 114,675
  • 90
  • 247
  • 350
  • I have added this to my AppDelegate, but failed to set a new Image. Can u hint me at what I might be missing? – Icky Nov 12 '10 at 11:40
  • no, i just failed. The image I set initially is seen in all my views. I'd like to change it to a plain image I also created an additionally add a title to it... – Icky Nov 12 '10 at 12:02
  • appearently, its not a String, that is returned there, but a UIImage. – Icky Nov 18 '10 at 11:28
  • and if anyone reads this: what I was missing was a [self setNeedsDisplay] .... I set all correctly, just needed to tell the bar to redraw itself! – Icky Nov 18 '10 at 11:46
  • You appear to be putting a UIImage* into the dictionary, but trying to read an NSString* out. How about this: - (void)drawRect:(CGRect)rect { UIImage* image=[navigationBarImages objectForKey:[NSValue valueWithNonretainedObject: self]]; if (image==nil) { image = [UIImage imageNamed:@"header_bg.png"]; } [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; } – AndrewCr Jan 21 '11 at 22:31
  • This method worked for me, although I had to change something: `code` - (void)drawRect:(CGRect)rect { if(navigationBarImages==NULL){ navigationBarImages=[[NSMutableDictionary alloc] init]; } UIImage *image=[navigationBarImages objectForKey:[NSValue valueWithNonretainedObject: self]]; if (image==nil) { image = [UIImage imageNamed:@"dq-locator-nav-image.png"]; } [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; } `code` – Corey Jul 08 '11 at 15:06
  • Any ideas about smooth transaction? because now it's just appears instantly. doesn't look nice. – Kęstutis Oct 02 '11 at 18:58
1

You can use this also

if([self.navigationController.navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)] ) {
        //iOS 5 new UINavigationBar custom background
        [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"navbg_ForiPhone5_Imagename.png"] forBarMetrics: UIBarMetricsDefault];
    } else {
        [self.navigationController.navigationBar insertSubview:[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"navbg_ForOtherIphone_Imagename.png"]] atIndex:0];
    }

`

Ravindra Bagale
  • 17,226
  • 9
  • 43
  • 70
Isuru Jayathissa
  • 478
  • 4
  • 15
  • Please edit your answer and format the code to make it readable. – kleopatra Dec 12 '12 at 10:42
  • Thanks for posting your answer! Please be sure to read the [FAQ on Self-Promotion](http://stackoverflow.com/faq#promotion) carefully. Also note that it is *required* that you post a disclaimer every time you link to your own site/product. – Andrew Barber Dec 19 '12 at 12:16
1

Mike Rundle and Casebash's code is great. I used [NSValue valueWithNonretainedObject:self] to avoid the copyWithZone error. Wrapping self in an NSValue object allows it to be copied into the navigationBarImages dictionary.


- (void)drawRect:(CGRect)rect
{
    NSString *imageName=[navigationBarImages objectForKey:[NSValue valueWithNonretainedObject:self]];
...}


- (void)setImage:(NSString*)image
{
    [navigationBarImages setObject:image forKey:[NSValue valueWithNonretainedObject:self]];
}
0

http://developer.apple.com/iphone/library/featuredarticles/ViewControllerPGforiPhoneOS/UsingNavigationControllers/UsingNavigationControllers.html#//apple_ref/doc/uid/TP40007457-CH7

Looking at Figure 1 in that link - would it be better to set the backgroundImage on your navigationbar not your navigationitem?

Boris
  • 1
0
 UIImage *image = [UIImage imageNamed: @"navigator.png"];

[_homeNavigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];

codercat
  • 22,873
  • 9
  • 61
  • 85
-2

Unfortunately, there is no support for using custom background images in a navigation bar in iPhone OS 3.0 or any previous versions. The only way to customize the appearance is to set the style and tint color. Not perfect, I know.

In your code you are trying to stretch the title view of the navigation bar to "go under" the right button. But this is impossible since the three views of a navigation bar (back button, title, and right button) are supposed to be in the same layer and are adjusted to not overlap. This is a feature.

I know there are a number of third-party apps that change the background image but they are "hacking" the system and are using unsupported private API:s or assumptions of the internal data structures of the navigation bar. These programs will most likely fail (crash or display incorrectly) in future versions of iPhone OS.

You most likely don't want to mess with this. Accept the fact that that you cannot (yet) have a custom background image in navigation bars. It hurts, I know. But if you hack the system and your app fails in a future versions of the OS, Apple will pull the app from the app store and you will lose all revenue until you have changed the app. It's your call...

Påhl Melin
  • 657
  • 1
  • 7
  • 14