UINavigationBar User Interface

I am trying to customize my own background for all of my NavigationBar (not just titleView), but struggling.

I found this chain

http://discussions.apple.com/thread.jspa?threadID=1649012&tstart=0

But I'm not sure how to implement the above code snippet. Is the code implemented as a new class? Also, where I install the UINavigationController , since I have an application built using the NavigationView template, so it does not run on my root controller according to the example

+50
objective-c iphone
Apr 01 '09 at 8:20
source share
15 answers

You just need to overload drawRect as follows:

 @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 
+29
Apr 27 '10 at 9:55 april
source share

Uddhav and leflay are right. This code works beautifully:

 @interface CustomNavigationBar : UINavigationBar @end @implementation CustomNavigationBar -(void) drawRect:(CGRect)rect { UIImage *image = [UIImage imageNamed: @"myNavBarImage"]; [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; } @end // this can go anywhere +(UINavigationController*) myCustomNavigationController { MyViewController *vc = [[[MyViewController alloc] init] autorelease]; UINavigationController *nav = [[[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil] objectAtIndex:0]; nav.viewControllers = [NSArray arrayWithObject:vc]; return nav; } 

You need to create CustomNavigationController.xib and put the UINavigationController in it and change the navigationBar class to "CustomNavigationBar".

+44
Aug 05 '11 at 16:15
source share

You must use the look and feel proxy to change the background and other style properties of the controls, such as UINavigationBar , UIToolBar , etc. in iOS 5.xx. However, they are not available for iOS 4.xx, so for backward compatibility you will need a hybrid solution.

If you want to support both iOS 4.xx and iOS 5.xx devices (i.e. your DeploymentTarget is 4.xx), you have to be careful in ending the appearance proxy server by checking the appearance at runtime "present or not.

You can do it:

 //Customize the look of the UINavBar for iOS5 devices if ([[UINavigationBar class]respondsToSelector:@selector(appearance)]) { [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"NavigationBar.png"] forBarMetrics:UIBarMetricsDefault]; } 

You should also leave the iOS 4.xx workaround that you might have implemented. If you applied the drawRect workaround for iOS 4.xx devices, as mentioned in @ludwigschubert, you should leave this at:

 @implementation UINavigationBar (BackgroundImage) //This overridden implementation will patch up the NavBar with a custom Image instead of the title - (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 will make NavBar look the same on both iOS 4 and iOS 5 devices.

+31
Oct 19 '11 at 15:08
source share

Category implementation is not recommended. iOS5 can help solve this problem. But for older APIs you can -

  • Subclass UINavigationBar say CustomNavBar and implement custom drawRect from lithium response.
  • For all CustomNavBar based on UINavigationControllers specify CustomNavBar as the custom class for your UINavigationBar .
  • For all UINavigationControllers code. Create an XIB using the UINavigationController and take the second step. Then specify the factory method in the code that loads the UINavigationController from nib and provides an IBOutlet .

Eg.

 [[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil]; UINavigationController *navController = self.customNavigationController; navController.viewControllers = [NSArray arrayWithObject:controller] 
+26
Jul 25 '11 at 17:55
source share

You can also override the drawLayer:inContext: method in the UINavigationBar category class. Inside the drawLayer:inContext: you can draw the background image you want to use.

 - (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)context { if ([self isMemberOfClass:[UINavigationBar class]] == NO) { return; } UIImage *image = (self.frame.size.width > 320) ? [UINavigationBar bgImageLandscape] : [UINavigationBar bgImagePortrait]; CGContextClip(context); CGContextTranslateCTM(context, 0, image.size.height); CGContextScaleCTM(context, 1.0, -1.0); CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage); } 

And as a complete Xcode demo to customize the look of UINavigationBar this and this can be useful.

+10
Feb 13 2018-11-11T00:
source share

I just found this blog post describing this topic very simply: http://web0.at/blog/?p=38

it helped a lot, they use the "drawRect" method to get the background setting.

+4
Aug 17 '10 at 20:30
source share

The category implementation will not work in iOS5, you should use the Uddhav Kambli tip to use CustomNavbar in iOS โ‰ค 5.

+4
Aug 04 2018-11-11T00:
source share

For all those who are having problems with UINavigationBar custom frames in iOS5, do this in the appropriate viewDidLoad methods:

 #if defined(__IPHONE_5_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0 if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){ [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"TitleBar"] forBarMetrics:UIBarMetricsDefault]; } #endif 

Please note that in my case the background image was named "TitleBar". You can put all your own background image.

+3
Nov 26 '11 at 21:15
source share

The problem that you will encounter is that if you use a navigation controller, the title of each page will overlap with your custom navigator. If your navigator contains the logo or name of your application, this is clearly unacceptable.

You can set the title of each view in the navigation stack to be empty, but some views force a title that you canโ€™t do anything (such as a photo picker). Thus, you can create an alternative image on the navigation bar with the same color or design as the logo on the navigation bar, but with an empty area to make room for overlay headings.

To switch navigation images as you like, add a property to the application delegate to save the name of the navigation image and replace the first line of the first example with the above two:

  YourAppDelegate* theApp = (YourAppDelegate*)[[UIApplication sharedApplication] delegate]; UIImage* image = [UIImage imageNamed:theApp.navBarName]; 

Then, in the first view of the controller that you click on the navigation stack, do something like this:

 - (void)viewWillAppear:(BOOL)animated { YourAppDelegate* theApp = (YourAppDelegate*)[[UIApplication sharedApplication] delegate]; theApp.navBarName = @"navBar_plain"; } 

Then, in the root view controller, do the same, but specify your navigation image with a logo, and it will be restored when the user navigates to it, and there is no contradictory name.

+2
Apr 14 '11 at 7:25
source share

Another approach is to use the UINavigationController delegate. This does not require subclassing / rewriting the UINavigationBar class:

 /* in the place where you init the navigationController: fixer = [[AENavigationControllerDelegate alloc] init]; navigationController.delegate = fixer; */ @interface AENavigationControllerDelegate : NSObject <UINavigationControllerDelegate> @end @implementation AENavigationControllerDelegate #define bgImageTag 143 - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { //this is for the future for implementing with the appearance api: if ([[navigationController navigationBar] respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [[navigationController navigationBar] setBackgroundImage:[UIImage imageNamed:@"header-logo-bg.png"] forBarMetrics:UIBarMetricsDefault]; }); } else { UIImageView* imageView = (UIImageView*)[navigationController.navigationBar viewWithTag:bgImageTag]; if(!imageView) { UIImage *image = [UIImage imageNamed:@"header-logo-bg.png"]; imageView = [[[UIImageView alloc] initWithImage:image] autorelease]; imageView.tag = bgImageTag; } [navigationController.navigationBar insertSubview:imageView atIndex:0]; } } @end 

https://gist.github.com/1184147

+2
Aug 31 '11 at 17:43
source share

IOS5 changes the zPosition value (from UINavigationBar's the deepest layer). Therefore, if you change this zPosition , the old way works.

eg.

 UINavigationBar *_bar = navigationController.navigationBar; // Insert ImageView UIImage *_img = [UIImage imageNamed:@"navibar.png"]; UIImageView *_imgv = [[[UIImageView alloc] initWithImage:_img] autorelease]; _imgv.frame = _bar.bounds; UIView *v = [[_bar subviews] objectAtIndex:0]; v.layer.zPosition = -FLT_MAX; _imgv.layer.zPosition = -FLT_MAX+1; [_bar insertSubview:_imgv atIndex:1]; 

This layer is the descriptor descriptor of the script, so you must import QuartzCore .

+2
Oct 14 2018-11-11T00:
source share

Here is an alternative solution that allows you to use your own subclass of UINavigationBar:

https://gist.github.com/1253807

+1
Sep 30 '11 at 2:00
source share

As Apple has already said, it is incorrect to override methods in Categories. Thus, the best way to customize the background of the UINavigarionBar is to subclass and override the -(void)drawInRect: .

 @implementation AppNavigationBar - (void)drawRect:(CGRect)rect { UIImage *patternImage = [UIImage imageNamed:@"image_name.png"]; [patternImage drawInRect:rect]; } 

To use this custom UINavigationBar , it must be set as the navigationBar property of your UINavigationBarController . As you know, this property is read-only. So what you need to do:

 - (void)viewDidLoad { [super viewDidLoad]; AppNavigationBar *nav = [AppNavigationBar new]; [self setValue:nav forKey:@"navigationBar"]; } 

It works for both iOS 5 and 4.3.

+1
Apr 01 2018-12-12T00:
source share

You can subclass the UINavigationBar and enable it like this, since the categories for drawRect will no longer work in iOS5

  navigationController = [[((^ { NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:[NSKeyedArchiver archivedDataWithRootObject:navigationController]]; [unarchiver setClass:[SAPHUINavigationBar class] forClassName:@"UINavigationBar"]; [unarchiver setClass:[UIViewController class] forClassName:NSStringFromClass([navigationController.topViewController class])]; return unarchiver; })()) decodeObjectForKey:@"root"] initWithRootViewController:navigationController.topViewController]; 
0
Aug 13 2018-12-12T00:
source share

For a static view (no animation at all) I use the standard iOS setBackgroundImage

But when I have an idea of โ€‹โ€‹what is animated (most likely resizing), I create a custom UIImageView and add it to the navigationBar so that I have more flexibility over it.

The fact is that if you just add it, it will be on top of the buttons and titleView, so I will manually save a copy of most of the subheadings, remove them from the parent view, add an ImageView image and add all the subzones back

It works for me

  UIImageView *navBackground = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"navigationBackgroundSample.jpg"]]; UIView *tempTitleView = [[self.navigationBar.subviews objectAtIndex:1] autorelease]; [[self.navigationBar.subviews objectAtIndex:1] removeFromSuperview]; [self.navigationBar addSubview:navBackground]; [self.navigationBar addSubview:tempTitleView]; self.navigationBar.clipsToBounds = YES; [navBackground release]; 

In this case, I have no buttons, and I found out that my View header is at index 1, if you have buttons, they should be somewhere in the subviews navigationBar array

I donโ€™t know what is at index 0, I donโ€™t know if this can work if you have a text name ...

0
Feb 19 '13 at 10:00
source share



All Articles