Having battled against the iOS API to theme my applications I was extremely pleased when iOS 5 introduced UIAppearance, allowing individual user interface elements or entire classes of elements to be themed in a particular way. Recently one of our apps required support for iOS 4.3 so I had to go back to my previous (more painful) method. I thought it might be useful to document both these methods to help anyone who might face a similar pain so hope this helps.

iOS5
In this example I am going to focus on theming a UINavigationBar but the principles in this article are the same for other elements. First lets look at how to change the background image of an individual UINavigationBar,

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"nav bar.png"] forBarMetrics:UIBarMetricsDefault];
}

However, if you want to have the same background image on every UINavigationBar within the app this can be problematic, you will have to set the background image in several places depending on where you create all of your UINavigationBars. Instead you can use the UIAppearance of the UINavigationBar.

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

This will theme every UINavigationBar element with the nav bar image, and the best thing is that in iOS 5 every UI component (or at least all of those I have used) implement UIAppearance so you can use this technique to theme all of your UIBarButtons, UIToolbars or any set of components you need to.

For most of us this will be the way we theme things from now on however, for some of us we still feel the obligation (or need) to support older versions (at least in the short term) so here is how to achieve the same results in iOS 4.3.

iOS 4

Objective-C categories, allows you to add additional functionality to objects that you are not the original creator of. You don’t even need the source to the original classes. Using this method you can override the drawRect method and customise the appearance of all of the UINavigationBars.

@implementation UINavigationBar (UINavigationBarCategory)
 
- (void)drawRect:(CGRect)rect {
    UIColor *color = [UIColor blackColor];
    UIImage *img  = [UIImage imageNamed: @"nav bar.png"];
    [img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.tintColor = color;
}
 
@end

Using Objective-C categories can be a useful and convent way of theming UINavigationBars and UIToolbars etc however, they do alter the appearance of all instances of this so it can throw off the appearance of other UI components that are part of the SDK. For example I recently looked to change the background of a UITableView with a category which worked well after I set the UILabels on the UITableViewCells background colour to clear. However, when I launched the UIImagePickerController the background was also changed on this and I had no easy way of setting the UILabels in its cells to have a clear background so the view looked horendus. Instead of using categories I created a base UITableView class that I extend to ensure that each UITableView is themed correctly.

Sources
This is a really useful resource that I drew from to theme my user interfaces in iOS4
Ray Wenderlich: iOS 5 User Interface Customisation