Custom colored UITabBar icons – an update

In a previous blogpost, which is still one of my most popular ones, I gave a method on how to create a tabBar with complete custom icons. It’s really more like a hack. But so far I haven’t found anything better yet. My method didn’t use any private API’s, and I have already succesfully submitted two apps in the App Store: Kust Afvalgids and Cultuurmarkt. The former one suffers from a little inconvenience: when you touch a given icon on your tabBar, you can still see the sort of “transparent” area covering the location of the icon, to indicate that this icon is active. You can get rid of that though. Here’s how.

A custom UITabBarItem implementation

To get rid of the annoying active state of an icon, all you have to do is implement your own class which inherits from UITabBarItem, and override the different icons. Then in the code you can create an instance of your custom UITabBarItem class, and assign it to the tabBarItem of your controller. Here’s how I implemented the subclass:

// CustomTabBarItem.h
@interface CustomTabBarItem : UITabBarItem {
    UIImage *customHighlightedImage;
    UIImage *customStdImage;
}

@property (nonatomic, retain) UIImage *customHighlightedImage;
@property (nonatomic, retain) UIImage *customStdImage;

@end
// CustomTabBarItem.m
#import "CustomTabBarItem.h"

@implementation CustomTabBarItem

@synthesize customHighlightedImage;
@synthesize customStdImage;

- (void) dealloc
{
    [customHighlightedImage release]; customHighlightedImage=nil;
    [customStdImage release]; customStdImage=nil;   
    [super dealloc];
}

-(UIImage *) selectedImage
{
    //return self.customHighlightedImage;
    return nil;
}

-(UIImage *) unselectedImage
{
    //return self.customStdImage;
    return nil;
}

@end

Two methods need to be overridden: selectedImage, which returns the icon you want to display in the active state; and unselectedImage, which returns the icon you want to display in the inactive state. As you can see in my code, I simply return nil. This indicates that I have no icons for both active & normal state. If you’ve read my previous blog post, you know I have just created different background images for the tabBar. Each background image already has the different images in it, so I don’t need separate icons for tabBarItems. If you do work like that, you just return the correct images in the correct methods (the parts which are commented out).

Now in each sub-controller of your tabBar, you make an instance of the CustomTabBarItem class, and assign it to self.tabBarItem. Example:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    CustomTabBarItem *tabItem = [[CustomTabBarItem alloc] initWithTitle:@"" image:nil tag:0];
        
    //tabItem.customHighlightedImage=[UIImage imageNamed:@"icon_active.png"];
    //tabItem.customStdImage=[UIImage imageNamed:@"icon_inactive.png"];
        
    self.tabBarItem=tabItem;
    [tabItem release]; 
    tabItem=nil;
}

Again, I provided sample code to show you how to specify the different images. Each time your view will appear, your tabBarItem will be set to your custom implementation. There is still one (little) problem: If you tap a selected tabBarItem twice, the active state will show. If you have a view transition, like a flip view animation, the active state will show. I have not found a way around this yet. I guess it’s somewhere in the internals of cocoa and I have no clue how to solve it. If you do find a solution, please let me know via the comments.

Conclusion

In my latest iPhone app, I have used the system of my previous blogpost to display different background images for the tabBar per controller. Then I have combined this with a custom tabBarItem implementation to get rid of the highlight state by returning nil for selectedImage & unselectedImage. If you don’t mind that this isn’t totally bug free, then this method is a good solution I think. Apps get approved with this code, since you don’t call any private API methods.

Update – For those of you who want to see an example of the two methods combined, here’s a piece of code:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self setCustomTabBarItem];
    
	for(UIView *view in self.tabBarController.tabBar.subviews) {
		if([view isKindOfClass:[UIImageView class]]) {
			[view removeFromSuperview];
		}
	}
	
    UIImageView *imgView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"custom_tabbar_image1.png"]] autorelease];
    imgView.frame = CGRectMake(imgView.frame.origin.x, imgView.frame.origin.y - 2.0, imgView.frame.size.width, imgView.frame.size.height);
	[self.tabBarController.tabBar insertSubview:imgView atIndex:0];
}

- (void)setCustomTabBarItem
{
    // Remove highlight from tabbar item:
    CustomTabBarItem *tabItem = [[CustomTabBarItem alloc] initWithTitle:@"" image:nil tag:0];
        
    self.tabBarItem=tabItem;
    [tabItem release]; 
    tabItem=nil;
}

19 Comments

  • Manish
    August 18, 2012 - 16:39 | Permalink

    Hey,

    Still not able to get rid of the transparent active state of tab.? I have overrided the 2 functions and returning nil.But still the active state is shown with transparent image.

  • Piero
    April 13, 2012 - 02:18 | Permalink

    Hello, great work! really, but with the UINavigationController don’t work, i add the navigation pragramtically:

    self.navigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];

    and then i pass the navigationcontroller to the UITabBarController, but in this way, i can see the Trasparent selected image…

    how i can do?

  • Nik
    March 2, 2012 - 10:07 | Permalink

    Obsolete with iOS 5 – iOS 5 provides all these customizations, minus the hacks…

    I still support iOS 4 but rather than implement both solutions I just let iOS 4 users live with the not-so-nice UI, standard tab bar.

  • Francesco
    February 18, 2012 - 02:01 | Permalink

    Dear Tom I have a problem, with your code I can change tabbar background but I see when an itme is selected beacause the item wash higlited, how can I solve the problem?thank you

    • Van Du Tran
      February 18, 2012 - 02:04 | Permalink

      He posted the solution, please read the code carefully.

      • Francesco
        February 18, 2012 - 02:50 | Permalink

        I re-try 3 times…I notice that if I try to initiWithTitle:@”XXX” on tabbaritem title is not display….image yes but not the title…:(

  • vandutran
    December 23, 2011 - 16:50 | Permalink

    Hi, I don’t get your code, what’ the difference between the first and second viewWillAppear()? Thanks.

  • Paolo
    December 12, 2011 - 17:06 | Permalink

    The following code should fix the issue when, if you tap a selected tabBarItem twice (or rotate the device), the active state will show.

    [self.tabBarController.tabBar imgView:background atIndex:0];
    [self.tabBarController.tabBar bringSubviewToFront:imgView];

    This way, the code brings background image view to front. Interesting is that UITabBarButtons (and the glossy effect) are under the background image, but still selectable.

    • Paolo
      December 12, 2011 - 17:08 | Permalink

      Mistyped sorry

      [self.tabBarController.tabBar insertSubview:imgView atIndex:0];
      [self.tabBarController.tabBar bringSubviewToFront:imgView];

  • Alex
    October 19, 2011 - 10:27 | Permalink

    Can you zip files and add a download link?

    Thanks!

    • October 28, 2011 - 12:36 | Permalink

      I’m sorry no. The examples are part of a bigger project, and I cannot put any of these files online. Snippets yes, not whole files/projects.

  • October 10, 2011 - 16:19 | Permalink

    Thanks man.

    I change
    - (void)viewWillAppear:(BOOL)animated
    to
    - (void)awakeFromNib

    Great post, thank you again.

  • braunsys
    September 21, 2011 - 12:26 | Permalink

    As I am not a developer, but merely an interested iPhone modder, I am a little confused, no, make that very confused…
    I have successfully changed the tab bar icons in my iP4 4.2.1 , but I can’t seem to change or remove the gray background icon when an icon is activated, i.e. when the “dialer/keypad” icon is activated, the gray background appears, I would like to completely remove or change the color/transparency of the background icon, could you please explain if this is possible and how do I enter the code using ssh and windows ?
    Any help would be greatly appreciated.
    Thank you

    • September 22, 2011 - 11:18 | Permalink

      I’m sorry, I don’t know how to mod your iPhone. I only know a bit how to make iOS applications, and this is what this article is all about. If you’re creating your own app with Cocoa, and you use a tabbar which you want to customize, then this is explained here. Anything else about modding, ssh’ing into your phone, or how to do it in Windows, is beyond the scope of this article (and beyond my knowledge to be honest)

  • Thiago Arantes
    September 17, 2011 - 01:47 | Permalink

    Hi,

    Could you provide an example of this code integrated with the code of the previous post. I tried to put both together but my highlight image still appears.

    Thanks,

    • September 22, 2011 - 11:16 | Permalink

      Tiago, I have updated the blogpost so you have an example.

      • shaojinkuang
        March 30, 2012 - 16:35 | Permalink

        hi,i want to know how you fix the issue when, if you tap a selected tabBarItem twice.3Q

  • Pingback: The Analog Guy » Custom colored UITabBar icons

  • Leave a Reply

    Your email address will not be published. Required fields are marked *

    *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>