Reputation: 159
I have a problem to change the background image of a UINavigationBar
for IOS version < 5. I read already about one good solution, which is based on method swizzling, but the problem of this solution is when I add the image it covers everything include the buttons on a navigation bar.
I found a solution which partially worked for me it is base on a following code:
@interface UINavigationBar (UINavigationBarCategory)
-(void)setBackgroundImage:(UIImage*)image withTag:(NSInteger)bgTag;
-(void)resetBackground:(NSInteger)bgTag;
@end
@implementation UINavigationBar (UINavigationBarCategory)
-(void)setBackgroundImage:(UIImage*)image withTag:(NSInteger)bgTag{
if(image == NULL){ //might be called with NULL argument
return;
}
UIImageView *aTabBarBackground = [[UIImageView alloc]initWithImage:image];
aTabBarBackground.frame = CGRectMake(0,0,self.frame.size.width,self.frame.size.height);
aTabBarBackground.tag = bgTag;
[self addSubview:aTabBarBackground];
//[self sendSubviewToBack:aTabBarBackground];
[aTabBarBackground release];
}
-(void)setRightButton:(UIButton*)button withTag:(NSInteger)bgTag{
if(button == NULL){ //might be called with NULL argument
return;
}
[self addSubview:button];
}
/* input: The tag you chose to identify the view */
-(void)resetBackground:(NSInteger)bgTag {
[self sendSubviewToBack:[self viewWithTag:bgTag]];
}
@end
I used this Category in my ViewWillAppear
methods like this:
-(void) viewWillAppear:(BOOL)animated {
UIImage *backgroundImage = [UIImage imageNamed:@"background_confernce_import_logo"];
if ([self.navigationController.navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)])
{
[self.navigationController.navigationBar setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];
}
else{
[[self.navigationController navigationBar] setBackgroundImage:backgroundImage withTag:8675309];
}
}
In else clause I call setBackgroundImage
. It is ok, but the problem is that if I have a right button on navigation bar of page 1 for example and go to page 2 after come back to page 1 the button is disappear. I should change the background image of navigation bar in every page in my application like this in viewWillAppear
method where I put the new image.
Any help will be appreciated. Under IOS 5 there are no such problem, but it should work on both versions.
Upvotes: 2
Views: 1566
Reputation: 27587
As per request, here comes my slightly naughty and not really polished hack. This is really just for making the OP happy. The right answer was given by sergio.
UINavigationBar+CustomDraw.m
NSString *gNavbarBackgroundImageName = @"default_navbar_background.png";
@implementation UINavigationBar (CustomBackground)
- (void)drawRect:(CGRect)rect
{
if (gNavbarBackgroundImageName != nil)
{
UIImage *image = [UIImage imageNamed:gNavbarBackgroundImageName];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
}
@end
UINavigationBar+CustomDraw.h
extern NSString *gNavbarBackgroundImageName;
And here comes the example usage in two view controllers...
FooViewController.m
#import "UINavigationBar+CustomDraw.h"
@implementation FooViewController
- (void)viewWillAppear:(BOOL)animated
{
gNavbarBackgroundImageName = @"foo_navbar_background.png";
[self.navigationController.navigationBar setNeedsDisplay];
}
@end
BarViewController.m
#import "UINavigationBar+CustomDraw.h"
@implementation BarViewController
- (void)viewWillAppear:(BOOL)animated
{
gNavbarBackgroundImageName = @"bar_navbar_background.png";
[self.navigationController.navigationBar setNeedsDisplay];
}
@end
Now let us assume you want to show a non-styled navigation bar, for example when displaying a Facebook login page (as provided by their SDK).
Use this to prevent any custom drawing:
gNavbarBackgroundImageName = nil;
Note Some of Apple's components use the UINavigationBar at places you might not have thought of. For example, the MPMoviePlayerController
uses a custom navigation bar for displaying the upper part of its UI - so that would be another case where you want to prevent custom drawing.
Upvotes: 0
Reputation: 69027
I hate to say it, but your approach (adding a subview to hold the background) will not work exactly for the reason you mention. Each time the navigation bar is redrawn, the subview will not keep its z-order (and thus it will cover other UI elements). This behavior is described by other sources (see this, e.g.)
If you don't want to use swizzling, you could override drawRect
in a category, so that the background is always drawn correctly. (this last option has the drawback that any navigation bar in your app will be drawn with the same background). This is a sample code I use:
@implementation UINavigationBar (CustomBackground)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: @"back.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end
A different approach could be:
UINavigationBar
;drawRect
;UINavigationBar
subclass.I haven't tried it, but it should work.
Upvotes: 1