Full Source code: https://github.com/boctor/idev-recipes/tree/master/CustomTabBar
Problem:
The Twitter iPhone App has a custom tab bar that is shorter than the standard tab bar, doesn’t have titles for the tab bar items and has a blue glow indicating when a section has new content. We want to recreate this custom tab bar.
Solution:
Just like segmented controls, the best way to customize the tab bar is to build it from scratch. In fact we’re going to start by using a recipe similar to what we used for custom segment controls:
- Create a button for every tab bar item.
- Manage the touches on the buttons so when one is selected, the others are deselected.
But how do we recreate the look of the buttons and how about that nice background for the tab bar?
The tab bar background
Looking at the images of the Twitter app, we find the TabBarGradient.png image which is 22px, exactly half the 44px height of this custom tab bar.
Taking a screenshot of the Twitter app and looking at it carefully reveals how the background is built:
- The top half is a stretchable image of TabBarGradient.png
- The bottom half is simply solid black
The custom tab bar asks its delegate for the background image and here is how we build it:
// Get the image that will form the top of the background UIImage* topImage = [UIImage imageNamed:@"TabBarGradient.png"]; // Create a new image context UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, topImage.size.height*2), NO, 0.0); // Create a stretchable image for the top of the background and draw it UIImage* stretchedTopImage = [topImage stretchableImageWithLeftCapWidth:0 topCapHeight:0]; [stretchedTopImage drawInRect:CGRectMake(0, 0, width, topImage.size.height)]; // Draw a solid black color for the bottom of the background [[UIColor blackColor] set]; CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, topImage.size.height, width, topImage.size.height)); // Generate a new image UIImage* resultImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return resultImage;
The buttons
The buttons have the following visual states:
- Drawn in gray when unselected
- Drawn with blue gradient when selected
- Embossed border is drawn around the selected item
A button has both an image and a background image and they can both be set for the various control states. When a button is selected, the blue gradient appears to be on top and the embossed border is behind it. So here is how we’ll setup the button:
- The button’s image for the normal state will be gray
- The button’s image for the selected/highlighted state will be blue
- The button’s background image for the selected/highlighted state will be the embossed border
The images for the tab bar items
A standard UITabBar only uses the alpha values of the tab bar item images. It doesn’t matter what color the images are, they will always appear in gray and blue. For our custom tab bar to be truly reusable, it will need to do the same thing.
But how exactly do we do this? It takes several steps:
- First we take the image and use CGContextClipToMask to generate a new image that has a white background and black content:
- Next we take this black and white image and use CGImageMaskCreate to create an image mask.
- Finally we combine the image mask with a background color.
For every tab bar item we generate two images: one with a solid gray background and another with a blue gradient background.
The blue glow
The blue glow is an image that is simply added to each button as a subview. In the Twitter app, a tab bar item will get a blue glow after the app has downloaded new content. It is a visual cue that there is more content in that section.
Our custom tab bar asks its delegate for the glowImage and it exposes a couple of methods to manage the glow: glowItemAtIndex and removeGlowAtIndex.
The current tab bar indicator
When a tab bar item is selected, a triangle at the top of the tab bar animates into place. We covered this animation in an earlier post. We use the code from that post to get the same animation for the custom tab bar.
Full Source code: https://github.com/boctor/idev-recipes/tree/master/CustomTabBar
Thanks for taking the time to write these… All very helpful tips! Keep it coming 🙂
Thanks a ton for sharing these with the community.
What license, if any, are you releasing these projects?
All the code is now available under the MIT License.
Really cool projects for ios features.
Thanks!
Would you please publish the license in the source files? The only reference I found to a license was this comment. Thanks!
Aaron, all the source on Github has the MIT License at the top of each file. It starts with: Permission is hereby granted…
I think your this beautiful code is corrupted in tableview in to tabBar..
I love this custom tool bar, thanks so much for sharing the code. Can you tell me how to solve the problem of viewWillAppear/viewDidAppear not being called for the uiviewcontrollers (assigned to each of the different tabs)?
In CustomTabBarViewController’s touchDownAtItemAtIndex you can call a method directly which would be similar to viewWillAppear. For an equivalent to viewDidAppear, in the same method you can call performSelector afterDelay:0 to delay the call to the next run loop.
Incredibly helpful! Thanks for posting.
Pure awesomesauce! I stuck it in my app just because this is sexy and I like it quite a bit more than the default tab bar, not to mention how it has the little ‘new data’ indicator, which I could for sure utilize. It’s a backup app, but I’ll find a way 😉
Thanks for that pice of code.
I trie to add a ViewController and each of them with it`s own Navigation Controller. But the NavBar never appears and the nav drill down did`nt work. I tired to solve this problem the hole day.
Maybe I´m stupid but I didn`t find a way for creating a tableView Drill down based on this example.
Maybe you can help?
Ive spent all day on this aswell, and only just realised that it doesn’t seem possible to use this with UINavigationControllers 😦
If Im wrong, I’d love to know how it can be done.
Jannik, Andy, Have you taken a look at the WordPress post? In there I use this custom tab bar, but the root view controller has a navigation controller. FreshlyPressedViewController (the vc for the first tab) then pushes another view controller using the nav controller from the app delegate.
Thanks for the code breakdown. Love this look over the default tab bar. How could i modify the code to use specific images for the selected tabs rather than the masking etc?? For whatever reason my “selected” icons look like garbage, i would like to go for a crisp shadowed look like the Airbnb app.
In CustomTabBar’s buttonAtIndex:width, instead of calling tabBarImage:size:backgroundImage for buttonImage and buttonPressedImage, use something like UIImage’s imageNamed: to use an existing image as-is.
Hi,
I am currently using this in my application and was wondering if there was a way that I could make it disappear. For example, I present the imagepicker and it is still there. Thanks a ton for sharing this code!
-Raymond
CustomTabBar is a UIView subclass, so you can simply set its hidden property to YES. You can also write a simple animation where you move it offscreen or fade it away:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
tabBar.alpha = 0;
[UIView commitAnimations];
Hi!
Thanks for the response. I’m still having a bit of trouble. In a class called home, which is the first selected view for the tab, there is a button which I want to make the tab bar disappear. I do so by calling:
#import “CustomTabBarViewController.h”
CustomTabBarViewController *tabView =[CustomTabBarViewController alloc] init];
tabView.tabBar.hidden=TRUE;
[tabView release];
But that doesn’t seem to do anything. Any recommendations?
Cheers,
Raymond
Hi,
Is there anyway to remove the gloss effect from the tab bar?
Thanks,
Matt
Hi Sir,
I think Raymond was right, been trying to hide it as well and it didn’t seem to work using hidden or setHidden. Even the alpha didn’t work.
Is there a solution or alternative fix for this?
Thanks,
MightyBoy
Take a look at the Reimagining WordPress post for another way to hide the tab bar. There the CustomTabBarViewController containing the CustomTabBar is the root controller of UINavigationController. When controllers are pushed, then the tab bar slides out of view.
Hi, thanks for this tab bar. It’s really beautiful and gives opportunity to continue customizing it for your needs. I’m now testing it in order to use in my project. I’ve used UINavigationControllers in each tab. The viewWillAppear/viewDidAppear issue is not as critical, but I’m concerned that when I push viewControllers to my navigation controllers in any tab, and than do popViewControllerAnimated:, the dealloc method of my view controllers is not called, so my app appears to be too memory consuming and sometimes crashes with memory warning 2.
Are there any ways to prevent this?
Thanks for this. Great code to learn from. I just downloaded the iOS 5 sdk and ran this in a iphone 5 simulator and notice the TabBarGradient.png is not stretching. Can you point me in the right direction to fix this.
Thanks again.
Figured it out. Place…
// Adjust our width based on the number of items & the width of each item
self.frame = CGRectMake(0, 0, itemSize.width * itemCount, itemSize.height);
…….
above
// Add the background image
UIImage* backgroundImage = [delegate backgroundImage];
…….
in CustomTabBar#(id) initWithItemCount:(NSUInteger)itemCount itemSize:(CGSize)itemSize tag:(NSInteger)objectTag delegate:(NSObject *)customTabBarDelegate
Thank you Mathew Sheets. Good fix.
thank you so much for your examples.
Hey man, i’m trying to use ur Class for my app and I’m having trouble running the app on device.
I get strange thread error () any ideas?
Even ur sample project get this error when building on device!
Great example. However, one thing CustomTabBar is missing is the ability to tap the currently selected tab to pop the selected tab’s navigation controller to the root view.
I’m trying to do this with no success. Perhaps you could help?
I’m able to see if the selected tab is the one already selected by stored an integer index (selectedIndex) in CustomTabBar. By comparing that to itemIndex in the touchDownAtItemAtIndex delegate method, I can see if the tab is already selected. This works fine.
However, for some reason, when I try to use [[viewController navigationController] popToViewController:viewController animated:YES]; nothing happens…
Any advice?
Did you ever solve this problem?
[…] here […]
[…] As iPhone apps mature, designers are exploring new navigation structures that can support an increasing breadth of content while keeping simple tasks accessible. There are now many examples of custom navigation, such as TweetBot’s flyout menus and Twitter’s label-less, contextual tab bar. […]
Thanks a lot for this tutorials,
Hi,
Thanks for the tutorial, but i having some problems. The CustomTabBar not rotating. I put the CustomTabBar in AppDelegate, and when the device rotating, the Custom TabBar not rotate, but other view is rotated. Please help me, i’ve stuck with this problem for 3 days 😦
Hi,
Thanks for your code.
But how can I make “hidesBottomBarWhenPushed” available with your custom tabbar?
Firstly, superb code.
Secondly, I’ve loaded in 5 blank viewcontrollers subclasses with navigation controllers, but if I try and get self.view.frame it always just prints back (320, 460). Is there any other way to get view bounds so I can size stuff programatically?
hi ,
Nice one, Thank for posting code.
I’d like to use this toolbar at the top of the view instead of the bottom—and I of course I moved the coordinates to move the toolbar but the arrow points up–does anyone have a revised version of the class that has the arrow pointing down when the user moves between the tabs?
This code does not seem to work on iOS 5–when I run the sample app I end up with the background not appearing behind the toolbar and even if I could fix that–when I point it at the UIViewController i created the toolbar code crashes with an exception where it is trying to get the size of the view.
Anyone had luck with this on iOS 5? I am trying to get the new toolbar to lay right below the UINavigation bar in my app
Anyone know what would be required to make this tab bar support orientation changes?
Hi Peter. Great addition. Have you made changes to make this work on iOS 5? If so, I would appreciate a link to those changes. Thanks
Hi, it’s really awesome! Thank you for this code. But I’ve got a little problem with UITabBar and UINavigationController – I cannot hide tab bar. Can you explain, how to hide it?
How to use CustomerTabBar with splitview, can you demo for me.Why I use with simulator, button tab is display, but i use with ipad button tab not display
Thanks
Thank you so much for this samples. It is very useful and it is working very well.
However, I am trying to switch from one tab to another pushing a button which is inside my tab 1.
How can I implement this?
[…] Oct 2 2011 As iPhone apps mature, designers are exploring new navigation structures that can support an increasing breadth of content while keeping simple tasks accessible. There are now many examples of custom navigation, such as TweetBot’s flyout menus and Twitter’s label-less, contextual tab bar. […]
[…] as a set of buttons each one related to it’s own View Controller. I guided on this link http://idevrecipes.com/2011/01/04/how-does-the-twitter-iphone-app-implement-a-custom-tab-bar/ to achieve the behavior. So the relevant part of code is as […]