Generally, the iPhone SDK is not that bad, however they left out an important feature that app developers really need - the ability to change the color of navigation buttons. Navigation buttons live on the very top of the application and are usually there to navigation backwards and forwards through views. Sometimes, though, they're used as confirmation or to save data that has been entered. This is when they need a different color. This tutorial is going to demonstrate how to create and place a blue button in the navigation controller.
A good example of a blue navigation button occurs when adding a new contact. When you start editing contact information, the Save button on the top-right corner of the app turns blue to let you know you're supposed to click that when you're finished.

Whereas the iPhone SDK lets you change the color of the entire navigation controller to anything you want, you can't change the color of an individual button. And unfortunately, getting the job done ourselves is a very tedious task.
There is really nothing built in to help us out here, so we need to start by creating an object to encapsulate the blue button. I called my object, BlueButton.
@interface BlueButton : UIButton {
BOOL landscape;
}
-(id)init;
@property BOOL landscape;
@end
As you can see, there's really not much going on here. BlueButton extends UIButton, so whoever is using this control can set the text and attach to events just as they would any ordinary button. Buttons in the navigation bar are different heights depending on the layout of the screen - landscape or portrait, so I added a property that an owning UIViewController would set whenever the orientation changes.
Now let's jump into the implementation of init. This is where the bulk
of the magic happens.
-(id)init {
if(self = [super init]) {
// The default size for the save button is 49x30 pixels
self.frame = CGRectMake(0, 0, 49.0, 30.0);
// Center the text vertically and horizontally
self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
UIImage *image = [UIImage imageNamed:@"blueButton.png"];
// Make a stretchable image from the original image
UIImage *stretchImage =
[image stretchableImageWithLeftCapWidth:15.0 topCapHeight:0.0];
// Set the background to the stretchable image
[self setBackgroundImage:stretchImage forState:UIControlStateNormal];
// Make the background color clear
self.backgroundColor = [UIColor clearColor];
// Set the font properties
[self setTitleShadowColor:[UIColor blackColor] forState:UIControlStateNormal];
self.titleShadowOffset = CGSizeMake(0, -1);
self.font = [UIFont boldSystemFontOfSize:13];
}
return self;
}
We're setting up a very basic button here. First I give it a frame that I default to size of the iPhone's 'save' button. Someone using the control can easily override this frame if needed. Next I make sure the text will be centered both vertically and horizontally.
The next stuff is probably the most confusing. I'm using a stretchable
image so I can use a single background image and make the button any
width I want. The stretchableImageWithLeftCapWidth property tells the
button it can stretch the image all it wants, but leave 15 pixels
unaffected, which will be where the rounded corners on the button are.
If we didn't set this property, it would stretch the image uniformly,
which will warp the rounded corners.
Now you're probably wondering where to get the background image. Well, unfortunately you're going to have to make it. I used the simulator to get a screenshot to start with and used Photoshop for the rest. As I mentioned earlier, there are two sizes of buttons required - one 30 pixels tall and one 24 pixels tall.

The navigation controller in my app is black, so these buttons are designed to work on that. They'll probably look ok on other colors, but you'll have to check and see. If not, you can always tweak them in Photoshop. Apple released a button similar to these in the UICatalog, however it was designed for the larger buttons located on views instead of in the navigation bar.
Ok, back to some code. If you remember, there is also a landscape property that changes the button to work in landscape mode. Here's the guts of the setter for that property.
-(void)setLandscape:(BOOL)value {
UIImage *image;
CGRect frame = self.frame;
if(value) {
image = [UIImage imageNamed:@"blueButtonSmall.png"];
frame.size.height = 24;
}
else {
image = [UIImage imageNamed:@"blueButton.png"];
frame.size.height = 30;
frame.origin.y -= 3;
}
UIImage *stretchImage =
[image stretchableImageWithLeftCapWidth:15.0 topCapHeight:0.0];
self.frame = frame;
[self setBackgroundImage:stretchImage forState:UIControlStateNormal];
}
The first thing I do is set the correct background based on orientation. There's an interested quirk that I needed in my app to make sure the button was always centered vertically when switching between landscape and portrait. When the orientation is changed from landscape back to portrait, the navigation already re-centers the button based on the 24 pixel tall button. Then, when I switch it out for the 30 pixel button, it now sits 3 pixels too low, so I need to move it up where it belongs.
All right now let's look at how to actually use this thing. You can run
the following code whenever you want to add a blue button, but I put
mine in the UIViewController's viewDidLoad function since I wanted it
there when the view was loaded.
BlueButton *blueSaveButton = [[BlueButton alloc] init];
[blueSaveButton setTitle:@"Add" forState:UIControlStateNormal];
[blueSaveButton addTarget:self action:@selector(addSite)
forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *button = [[UIBarButtonItem alloc]
initWithCustomView:blueSaveButton];
self.navigationItem.rightBarButtonItem = button;
[button release];
[blueSaveButton release];
The first three lines are basic button initialization code. Using
initWithCustomView gives you the ability to create a navigation button
from any view you want - in this case our blue button. You then simply
set self.navigationItem.rightBarButtonItem to the new button and
you're done. Here's what this code gives you:

Well there you go. They didn't make it easy, but it is doable. You can download the blue button images I created below and use them in you're own app if you want.
Source Files:
Thanks for the tutorial. My question is a little off-topic, but I can't find the answer anywhere, and this tutorial almost touches on the issue.
My app works in portrait, with a navigation bar. I want to have a horizontal navigation bar (readable with the device in landscape mode) when the iPhone is turned to landscape, and the navigation bar thinner, according to the HIG.
When I detect an orientation change to landscape, I run a CGAffine transform on the navigationBar so that it will be *readable* in landscape mode. Fine. I change its frame to place it along the long axis of the device, and make it thinner. Fine. But the title text and back button won't scale to fit the new navigationBar after the transform. They are too big, and sitting partially off of the bar.
The transform seems to mess things up. How do I rotate a navigation bar to landscape mode while making it thinner and scaling the items in the bar to the new thinner size? Even a link to useful info would be greatly appreciated.
Can you not just use UIBarButtonItemStyleDone instead of UIBarButtonItemStylePlain? This makes your button blue.
I definitely remember setting that in Interface Builder and it having no affect. There might be some way to do it in code. I'll have to investigate further.
[language] self.navigationItem.rightBarButtonItem.style = UIBarButtonItemStyleDone; [/language]
That works fine if your navigation bar is the standard color, but if your bar is black, then setting it to "Done" doesn't make the button blue.
bbItem = [[UIBarButtonItem alloc] initWithTitle:aString style:UIBarButtonItemStyleDone target:nil action:nil];
there is also a UIButtonTypeContactAdd type of UIButton, but I haven't used it
Cool! Great!
Thank You. It's been very helpful.
Have you seen ButtonFactory on the iPhone Appstore, cool app for creating buttons
Hi,
First of all, thanks for share your code.
I developed similar solution, but I have a problem, when i use this solution in a button added to any UIView, it runs perfectly. But, if I add it to a bar button (f.s. right bar button)
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithCustomView:blueSaveButton];
the button doesn't resize automatically, it maintains the initialization frame (CGRect) size.
I have the same problem, even in when adding to UIView, if I create the blueSaveButton with buttonWithType:UIButtonTypeCustom
Any idea to solve the problem ¿?
Thanks a lot!
Ivan
Thanks, good explanation.
Thanks for the tutorial! Just a minor tweak, I get a closer match to the native buttons using a slightly smaller gray shadow. Also, as of OS 3.0, the shadow and font properties are deprecated. Here's the up-to-date code if anyone is interested:
[language] [self setTitleShadowColor:[UIColor grayColor] forState:UIControlStateNormal]; self.titleLabel.shadowOffset = CGSizeMake(0, -0.75); self.titleLabel.font = [UIFont boldSystemFontOfSize:13]; [/language]
All you need is this:
[language] // Highlight the stop button so they can tell it's still playing self.navigationItem.rightBarButtonItem.style = UIBarButtonItemStyleDone; [/language]
to set it back to normal, just change the style back to bordered.
Good tutorial. Although it seems you can get the same effect as the tutorial with UIBarButtonItemStyleDone, I'm always interested in techniques for customizing standard UI widgets and this opens the door to further customization with colors, textures, etc.
The same method as this tutorial can actually be used to put a custom back button in a UINavigationBar as well. Pretty neat stuff.
You know, you can also colorize the navigation bar background in a different color than the button, so you dont need image but 10 lines of code....
Not to detract from your tutorial, but if you're finding you need a save button then the chances are you're not doing it right. The iOS way of doing things is that everything is "saved" straight away. Perhaps what you really want is a "next" or "commit". In the former case a standard nav bar button would do, and for the latter you probably don't want it on the nav bar.
I realise this is a couple of years on from your post - but for balance I thought it was worth pointing out.
(originally I notice that this "Add Comment" box has a "save" button. It should probably be something like "Post" or "Submit" - but that's a minor nitpick ;-) )
please mention the header files of the codes....for the new user it make confusion.....thanks for this Application
pretty detailed and a very well written example of adding a custom button to navigation bar. This tutorial indeed helped my team implement custom button in a project.
Hi everyone, i'm doing a joke app for iphone. i have 12 categories. There is a category settings to disable categories. while i used to scroll down to see all categories there is problem that the categories getting changed like showing 12 ctgry instead of 1 ctgry like wise and the save function working for only 8 categories. I expect support from you guys. Thank you
AWESOME post! Thank you so much!!!