32

I was crawling Dribble and found the attached design. I was wondering how to do a custom navigation bar like this. I mean how create the navigation bar once and reuse it implicitly for every view controllers.

I was thinking about having a kind of root view controller and inherit for other view controllers, but I don't know how to do this.

Any idea or link will be appreachated!

Cheers.

Cyril

Nav bar image

Cyril
  • 1,584
  • 1
  • 16
  • 32

6 Answers6

8

Thanks to iOS5 you are now able to customise the appearance of a UINavigationBar without having to subclass or create a category.

The following code block (put it in your applicationDidFinishLoading: method) will change the UINavigationBar for the whole application to whatever image you give it.

Note, this will ONLY work in iOS5

[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"nav bar.png"] forBarMetrics:UIBarMetricsDefault];

However, you are also able to change the appearance of a single UINavigationBar depending on what view controller you're in by using the following code in viewDidLoad.

[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"nav bar.png"] forBarMetrics:UIBarMetricsDefault];

The above code is solely discussing the new ways to customise the UINavigationBar appearance thanks to iOS5. However, it does not discuss the way that the buttons have been implemented.

However, adding the buttons is a different game altogether. For this, I would recommend subclassing UINavigationBar, and then adding in the buttons where needed through that. You could probably even get away with just a standard UINavigationBar but custom UIBarButtonItems that run off a particular view.

For example:

UIView *rightButton = [[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 30.0f, 30.0f)] autorelease];
[rightButton addSubview:[UIImage imageNamed:@"rightButtonImage.png"]];

UIBarButtonItem *rightButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:rightButton] autorelease];
[rightButtonItem setAction:@selector(rightButtonAction:)];

I haven't tested that code so it isn't a copy/paste solution, but it gives you an idea of what needs to be done to accomplish "custom" looking UIBarButtonItems.

Good luck!

Sebastien Peek
  • 2,468
  • 2
  • 21
  • 32
6

In older iOS versions you have to subclass UINavigationBar i.e.:

@interface CustomNavigationBar : UINavigationBar
@end

@implementation CustomNavigationBar

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.opaque = YES;
        self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"CustomBackground"]];
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    // Skip standard bar drawing
}

@end

To use a custom navigation bar in your view controller, you should change a standard class name to CustomNavigationBar in XIB.

Also, you can set the custom navigation bar programmatically:

UIViewController *tempController = [[[UIViewController alloc] init] autorelease];
UINavigationController *navigationController = [[[UINavigationController alloc] initWithRootViewController:tempController] autorelease];

NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:navigationController];
NSKeyedUnarchiver *unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:archive] autorelease];
[unarchiver setClass:[CustomNavigationBar class] forClassName:@"UINavigationBar"];
UINavigationController *customNavigationController = [unarchiver decodeObjectForKey:@"root"];

UIViewController *contentController = [[[ContentViewController alloc] init] autorelease];
customNavigationController.viewControllers = [NSArray arrayWithObject:contentController];

Now customNavigationController has the custom navigation bar.

Vadim
  • 9,165
  • 7
  • 33
  • 58
3

set a custom background for the NavigationBar

UIImage *navBackground =[[UIImage imageNamed:@"navbarBackground"] 
                 resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
[[UINavigationBar appearance] setBackgroundImage:navBackground forBarMetrics:UIBarMetricsDefault];

then in your View Controller set custom views for left, rightBarButtons and title.

self.navigationItem.titleView = customTitleView;
self.navigationItem.leftBarButtonItem = customBarButton;
self.navigationItem.rightBarButtonItem = customBarButton2;
agilityvision
  • 7,781
  • 2
  • 27
  • 28
  • I have another question @eric-lars0n. How would I actually make the navigation buttons like in the picture? Do I have to specify a UI frame the size of the square of the button, and add it as a subview for the nav bar? – n00shie Nov 15 '12 at 01:31
1

You would need to make your own UINavigationBar subclass, and use in places where you would need a navigationController.

In this custom class is where you will draw the background, buttons, text, etc.


Update

Actually, taking a closer look at this example, it appears to be a UIToolBar. You can assign navigation methods to the buttons like popViewController: etc. For the "Confirm Information" and progress indicator, you can use a label and an image. For the right button, its just a graphic.

Of course, the example you provided is simply a concept, and not an actual app. But with some creativity, a few hours of coding and a few more hours of graphics design, you can achieve this same interface.

WrightsCS
  • 49,871
  • 22
  • 132
  • 180
  • 3
    In fact, this motivates me to write a custom navigation controller. If I get something up and running, I will post it to github and update with a link. – WrightsCS Dec 17 '11 at 22:31
  • UINavigationController class reference: "This class is not intended for subclassing." However, you may find my post in the following question to be of help: http://stackoverflow.com/questions/6398869/how-to-assign-my-customnavigationbar-to-a-uinavigationcontroller – Luke Dec 17 '11 at 22:45
  • 2
    UINavigationBar subclassing, not controller. – WrightsCS Dec 17 '11 at 22:49
  • Interesting, I really need to see your implementation to understand how it works :) – Cyril Dec 18 '11 at 18:23
0

You can use the stock UINavigationController and hide the UINavigationBar.

Then, make your own subclass of UIViewController which has all of the navigation elements, and then a flexing size view where the contents go. Make all of your classes subclass this element and draw into the view. The button simply has to call [self.navigationController popViewControllerAnimated:YES] and the UILabel at view just has to set its text to self.title.

Tim
  • 14,221
  • 6
  • 37
  • 62
  • I was thinking about a solution based on this, creating a custom root view controller managing a custom navbar and animations, but I don't know how to use it with inheritance, any idea? – Cyril Dec 18 '11 at 18:24
0

Using Category, add code below in your delegate file (.m)

@implementation UINavigationBar (UINavigationBarCategory)

- (void)drawRect:(CGRect)rect
{
    UIImage *navBg = [UIImage imageNamed:@"NavBar.png"];
    [navBg drawInRect:CGRectMake(0, 0, 320, 44)];
}
@end

Edit:

Using Category is not a good way, I wrote a demo without using Category, click here.

xda1001
  • 2,399
  • 14
  • 18
  • Apple engineers advise to never ever use a category to customize navigation bar appearance. – Vadim Feb 13 '12 at 19:59
  • @SteveCotner see my edit, I wrote a demo to customize navigation bar. In iOS5 or above, using category drawrect can't change the navigation bar apperence, and if you use like MFMailComposeViewController, its apperence looks ugly. – xda1001 Jul 10 '12 at 08:27
  • Thanks. In iOS 5 (and 6... shh...), I made a category and overrode sizeThatFits: to change the appearance. Hacky, I know, as it's sometimes called more than once on a single view. But it has worked so far and kept me from having to customize it in every view controller. Apple wouldn't reject an app for doing that, would it? – Steve Cotner Jul 10 '12 at 09:17