Monthly Archives: October 2010

Custom colored UITabBar icons

On the iPhone, there is no such thing as a menu. When you create an application, you will usually work with a drill-down structure called NavigationController, or with the TabBarController. The difference between them is that the NavigationController ties screens together with increasing granular information, and the TabBarController lets you switch between screens which aren’t really connected to each other. It’s about that TabBarController I want to write this blog post about. Or rather, about a “missing feature” in it.

The TabBarController can be customized with either custom titles, custom icons or both. If you want custom icons, you will see that even though you created them in different colors, the iPhone SDK will always render them in blue when active, and in grey when inactive. Wouldn’t it be nice if you could have them in any color you’d like? I know designers would like that. More often than not, they design these pieces of the UI without remembering that in the end these icons will be blue/grey. But unfortunately there is no obvious way of achieving this. But when means are limited, creativity can help you solve many issues.

Custom colored icons

There is a trick to make your designer happy, and give him his colored icons. However, it still is a work around, and the method isn’t very stylish. It comes down to this:

  • Don’t give icons or titles to your different UITabBarItems
  • On each view of the UITabBar, set a different images as tabbar
  • Each different image has both the TabBar background in it, as well as all the icons. But the currently active page icon should be highlighted

Here are some examples:

  • background_calendar.png
  • background_clock.png
  • background_location.png
  • background_lightbulb.png

I have four tabs, so this means I need four different backgrounds for my UITabBar. On each view, I first need to remove the current background, and then I just add the background for current screen. In each ViewController I add the following:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
	for(UIView *view in self.tabBarController.tabBar.subviews) {
		if([view isKindOfClass:[UIImageView class]]) {
			[view removeFromSuperview];
		}
	}

	[self.tabBarController.tabBar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background_location.png"]] autorelease] atIndex:0];
}

When you don’t remove the subviews, and just try to insert your background image at index 0, then your image won’t swap. Hence we need to remove the existing subview first, and then later insert our new one. If you now build and run your application, you should see the tabbar, and if you hit each tabbar icon, you will see that the correct one is activated. And all in color!

Update 14 Sept. 2011: I wrote a follow-up blogpost here: http://blog.theanalogguy.be/2011/09/14/custom-colored-uitabbar-icons-an-update/

Custom background for UINavigationBar

When you’re working on an iphone app, more often than not, you’ll be working with the standard SDK elements and then customize those. For a recent project, I had to work with a navigation controller. And of course, the UINavigationBar needed to be customized with a proper image.

Now I had never done this before, and as usual when I don’t know how to do some task, I look in one of my two books. If the answer isn’t there, then Google comes to the rescue. So to customize the background of a UINavigationBar wouldn’t be too much of a problem I thought. And indeed it wasn’t, but I first implemented a wrong solution:

How to do it incorrectly

In the viewWillAppear:(BOOL)animated method of the ViewController, I wrote this:

[self.navigationController.navigationBar insertSubview:[[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"title_bar.png"]] autorelease] atIndex:0];

Basically, it inserts an image with filename “title_bar.png” as a subView into the UINavigationBar. This works fine. In fact, I couldn’t see anything wrong with it. So I went ahead, and added it elsewhere in the code too.

So if this works, what is wrong with it? The behavior is unpredictable. In my title bar, I set the title of the current view, and I added a button on the right hand side. Sometimes the button wouldn’t render, sometimes the title wouldn’t render. Sometimes the behavior was correct only after I went to another view, and then came back to this one. So to keep it short: it is unpredictable, and you don’t want to do it this way.

How to do it correctly

To make this work, you don’t have to write a lot of code. All you need to do is subclass the UINavigationBar class, and implement the drawRect method yourself. This will override the default behavior with what you implement. So each time drawRect is called, we just make sure the “title_bar.png” image is added:

@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
	UIImage *image = [UIImage imageNamed: @"title_bar.png"];
	[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end

The drawRect method is automatically invoked when the UINavigationBar will be rendered. Each time this happens, the image will now be automatically drawn in the title bar. Beware though, this is for all UINavigationBar’s in your project.