Full Source code: https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar
Problem:
Apps like Instagram, DailyBooth and Path™ have what looks like a standard UITabBarController, but the center tab bar is raised or colored. How do we recreate this look?
Solution:
These tab bars look pretty standard with the exception of the center item, so we’ll start out with a standard UITabBarController which contains a UITabBar.
Looking at the images inside each app, it is quickly apparent that the middle tab bar is simply a custom UIButton.
A UITabBar contains an array of UITabBarItems, which inherit from UIBarItem. But unlike UIBarButtonItem that also inherits from UIBarItem, there is no API to create a UITabBarItem with a customView.
So instead of trying to create a custom UITabBarItem, we’ll just create a regular one and then put the custom UIButton on top of the UITabBar.
Our basic recipe is then to create a subclass of UITabBarController and add a custom UIButton on top of the UITabBar.
If the button is the same height as the UITabBar, then we set the center of the button to the center of the UITabBar. If the button is slightly higher, then we do the the same thing except we adjust the center’s y value to account for the difference in height.
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height); [button setBackgroundImage:buttonImage forState:UIControlStateNormal]; [button setBackgroundImage:highlightImage forState:UIControlStateHighlighted]; CGFloat heightDifference = buttonImage.size.height - self.tabBar.frame.size.height; if (heightDifference < 0) button.center = self.tabBar.center; else { CGPoint center = self.tabBar.center; center.y = center.y - heightDifference/2.0; button.center = center; } [self.view addSubview:button];
You might notice that in the code we don’t add the button as a subview in viewDidLoad. This is because we have our UITabBarControllers within a UINavigationController. When viewDidLoad is called, our UITabBarController’s view is the entire height of the screen. If we add the button as a subview in viewDidLoad we’d have to manually account for the navigation bar or properly setup the button’s autoresizingMask both of which complicate the code. But after the UITabBarController is pushed onto the UINavigationController stack, the UITabBarController’s view is auto resized to account for the navigation bar. So we delay adding the button as a subview until the UITabBarController’s has been pushed onto the UINavigationController stack. We do this by registering for the navigationController’s willShowViewController callback.
Full Source code: https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar
[…] View full post on Hacker News […]
[…] Jak na custom button v UITabBarController 0 iDev Recipes: Apps like Instagram, DailyBooth and Path™ have what looks like a standard UITabBarController, but the center tab bar is raised or colored. How do we recreate this look? […]
[…] Recreating The Raised Center Tab Bar Button of Instagram, DailyBooth & Path™ « iDev Recipesidevrecipes.com […]
[…] für iPhone-Entwickler: Die, auf die Erstellung von iOS-Applikationen spezialisierte Webseite iDevrecipes erklärt interessierten iPhone-Entwicklern in diesem Artikel wie sich die in Instagram, DailyBooth […]
Excellent info! I can’t wait to try it out.
[…] Great example of customizing the UITabBarController Full Source code: https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar Problem: Apps like Instagram, DailyBooth and Path™ have what looks like a standard UITabBarController, but the center tab bar is raised or colored. How do we recreate this look? Solution: These tab bars look pretty standard with the exception of the center item, so we'll start out with a standard UITabBarController which contains a UITabBar. Looking at the ima … Read More […]
[…] Recreating The Raised Center Tab Bar Button of Instagram, DailyBooth & Path […]
How did Instagram implement its bottom iPhone bar?…
Here is the blog post associated with that code: http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/…
This is great, but you’ll find that the behavior is erratic if any of your tab bar controller’s child view controllers hide the navigation bar. To fix the problem, add the line below to addCenterButtonWithImage:highlightImage.
centerButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
That way the center button will move up and down with the tab bar as the navigation controller adjusts its content view’s bounds.
Thanks for the tutorial!
Hi, thanks for the tip, but I’ve a problem.
I’ve a TabBarController application and this is my didFinishLaunching method in app delegate:
UIImage *buttonImage = [UIImage imageNamed:@”post-button2.png”];
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
NSLog(@”Button size: %f, %f”, buttonImage.size.width, buttonImage.size.height);
button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
CGFloat heightDifference = buttonImage.size.height – self.tabBarController.tabBar.frame.size.height;
NSLog(@”self.tabBarController.tabBar.frame.size.height: %f”, self.tabBarController.tabBar.frame.size.height);
NSLog(@”heightDifference: %f”, heightDifference);
NSLog(@”%Tabbar: %f, %f”, tabBarController.tabBar.center.x, tabBarController.tabBar.center.y);
if (heightDifference < 0)
button.center = tabBarController.tabBar.center;
else {
CGPoint center = self.tabBarController.tabBar.center;
center.y = center.y – heightDifference/2.0;
button.center = tabBarController.tabBar.center;
}
NSLog(@"%Button: %f, %f", button.center.y, button.center.x);
[tabBarController.view addSubview:button];
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
The output is this: http://i.imgur.com/IVzKw.png
Why this?
Hello, thank you for this tutorial !!
My custom UITabBarController is using NavigationController as viewControllers.
All is displayed correctly BUT:
When my navigation controller want to display the “next” controller with the property hidesBottomBarWhenPushed (to hidde the TabBarController)… the button stays displayed and the TabBar is hidden..
What is the best solution to hidde the Centered button simultaneously with the tabbar ?
fvisticot, what I had to do to get the button to move with the tab bar was to add the view to tab bar itself, vs adding it to the main view. Here’s my code:
CGPoint center = self.tabBar.center;
center.y = self.tabBar.frame.size.height – buttonHeight/2.0;
drinkButton.center = center;
[self.tabBar addSubview:drinkButton];
How do you listen for a click on the middle bar? To display a modal view?
I made my appDelegate use the UITabBarControllerDelegate protocol, then in addCenterButtonWithImage, I added the target to the button go to self.delegate with @selector(buttonPress)
When I add the button as a subview of the tabbar, it is no longer visible. Is there another trick to get this to work as expected?
Full code:
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[button setBackgroundImage:highlightImage forState:UIControlStateHighlighted];
CGFloat heightDifference = buttonImage.size.height – self.tabBar.frame.size.height;
if (heightDifference < 0){
button.center = self.tabBar.center;
}else{
CGPoint center = self.tabBar.center;
center.y =self.tabBar.frame.size.height-(buttonImage.size.height/2.0);
button.center = center;
}
// action for this button
[button addTarget:self action:@selector(buttonEvent) forControlEvents:UIControlEventTouchUpInside];
I created a method to handle this button.
– (void) buttonEvent{
}
NOTE: I just have one button with this. If you have multiplies buttons, pass it in the method.
[self.tabBar addSubview:button];
Same problem, I tried the code posted in this thread but the button in the middle is no longer clickable, it selects the central tab instead.
@emafuma I had the same problem with the button in the middle not being clickable, and it selecting the centre tab instead. The solution was to add this in viewWillAppear:
[self.tabBar bringSubviewToFront:centerButton];
This is an outstanding issue, per Jack’s comment. Does anyone have a solution?
I ran into this problem then realized that I had to adjust the frame of the subview as I was no longer drawing it to the main view. This did the trick for me, hope it helps.
I figured out what was causing this. It’s this code:
if (heightDifference < 0)
button.center = self.tabBar.center;
else
{
CGPoint center = self.tabBar.center;
center.y = center.y – heightDifference/2.0;
button.center = center;
}
I removed it and manually centered's the button's frame (my app doesn't have a landscape view, so I guess it's not much of an issue).
change two lines. one to make the button frame relative to the tabbar instead of view (i.e. center button frame 0 is tabbar’s y)
and add the button to tabBar view
change:
center.y = center.y – heightDifference/2.0;
to:
center.y = center.y – self.tabBar.frame.origin.y – heightDifference/2.0;
and then:
[self.view addSubview:button];
to:
[self.tabBar addSubview:button];
Here ya go: ya go Here ya go:: Recreating The Raised Center Tab Bar Button of Instagram, DailyBooth & Path? iDev Recipes
I think your approach is no good. I checked the coding and you subclass UITabBarController however the documentation says ” This class is not intended for subclassing. Instead, you use instances of it as-is…”
I wonder if anyone had an app approved using this approach.
Is it possible to support Landscape left and right for the Tab controller?
I’m implementing shouldAutorotateToInterfaceOrientation in ‘BaseViewController’ and returning YES for both these modes as well as Portrait.
The only problem is that when the screen is rotated to either Landscape orientation, the center button looks like a normal tab bar instead of the raised version.
Just add an autoresizingMask to the button. Here is a change that does that
Peter, great tutorial, thanks for doing these and please keep them coming.
I’m glad you explained this:
“You might notice that in the code we don’t add the button as a subview in viewDidLoad.”
That was one of the first questions I had, as I examined (tried to comprehend) the code.
However, when I comment out the willAppearIn method in the InstagramViewController and add this line to the viewDidLoad method (after the NSArray objects are added):
[self addCenterButtonWithImage:[UIImage imageNamed:@”cameraTabBarItem.png”] highlightImage:nil];
Everything seems to run fine. I’m on iOS 4.3 (ran on device & simulator).
Is this extra step no longer necessary or perhaps I’m missing something.
Thanks again!
Kudos for actually checking the code! You’re right. The reason it now works in viewDidLoad is the commit yesterday that added an autoresizingMask to the button (to support rotation). If you comment out that line, you’ll then see that doing it in viewDidLoad will stop working. Also, if you set a breakpoint in both viewDidLoad and viewWillAppearIn and at the gdb prompt type po [self view], you’ll see that in viewDidLoad the view is 480px high and in viewWillAppear in it is 416px high.
Thanks for this great tutorial. I am having problems in my app that after a modal view controller has been on screen all the viewcontrollers in this raisedcenter tabbarcontroller doesn’t call viewdidappear anymore. Any suggestions?
Sorry found out I forgot to call super viewdidappear. NEWB error 🙂
[…] I’m trying to follow the code here : Recreating The Raised Center Tab Bar Button of Instagram, DailyBooth & Path? iDev Recipes […]
[…] http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/ […]
This was just what I was looking for! However, I have a action on the center button and im trying to get it to display a View Controller.
In my action method
-(void)goSearch
{
self.selectedViewController =[self viewControllerWithTabTitle:@”Share” image:nil];
}
I call the viewControllerWithTabTitle method again to show that view. However, the view moves up by 20px or so and when I call to load a modal view, the modal view is IN FRONT of the tabBar. any help?
Great Post!
I implement it on the app delegate and add a target to another view… everything works fine.
But I have to open another view when I click on the button, but it doesn’t work.
can you help me?
thanks
I’m really happy with this tutorial, except for one thing: how do I launch a modal view controller from the center button?
I’ve opened up a ticket on Stack Overflow about the question, please feel free to comment here or there if you have an answer! I’ll update as well if I find out the answer first. 🙂
Here’s the link:
http://stackoverflow.com/questions/7238418/how-do-i-launch-a-modal-view-from-a-custom-uitabbar
Found an answer! Here’s what did the trick: I had to move the raised center button’s code from the AppDelegate to the ViewWillAppear: method of my default tab.
The reason is that the AppDelegate can’t support the presentModalViewController method. (The AppDelegate is not a subclass of UIViewController and therefore doesn’t work for this.)
The tab’s ViewController, however, definitely works with this method, and the problem is solved!
Check out the above link on Stack Overflow for the code.
Why in willAppear method you passed the navigationControl as an argument?
If I pass “nil” as object in this message:
[viewController performSelector:@selector(willAppearIn:)withObject:nil];
it continues to work..why?
Is there a way to have the custom button(s) stay highlighted when selected/tapped?
Thanks in advance!
[…] Interested in creating a custom center button for your app? Here’s a link to a short tutorial, with code (read the comments for some useful details): http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/ […]
Hello,
i must say ‘amazing!’ 🙂 but i want to ask 2 question to you.
How can i highlighted center button on click?(Like a TabBarItem)
And can we remove TabBarItem highlighted mask? I want to see only blue mask. I want remove white.
The answer to make the center button a real button
[button addTarget:self action:@selector(buttonEvent) forControlEvents:UIControlEventTouchUpInside];
– (void) buttonEvent{
[self setSelectedIndex:2];
}
you are absolutely RIGHT!!!!
thanks
If you use UIControlEventTouchDown it behaves more like the tab bar items.
Hello,
The tutorial is great and I successfully created the tabBar and the button. When using the code from above, I managed to have the center button logged and seems to work, but only thing is the presentModalView do not work….
My CustomtabBar was orginally a NSObject class, but then I change it to an UIViewController class but still it does not work.
Can anyone show me the light on how to make it work…. thank you =)
.m
#import “InfoViewController.h”;
[button addTarget:self action:@selector(ButtonAction) forControlEvents:UIControlEventTouchUpInside];
– (void) ButtonAction{
NSLog(@” Button pressed”);
//NSLog logged the event, but modal view not show.
/* InfoViewController *infoView = [[[InfoViewController alloc] init] autorelease];
[self presentModalViewController:infoView animated:YES];*/
}
[…] of the component was inspired by this post found at iDev Recipes. The post demonstrates how to make a center button in a UITabBarController. I made a featured […]
Hey guys, great post. I am just wondering how can I get the tabs to actually display a view controller? (Minus the button in the middle)
i tried the [self.tabBar addSubview:button];
to hide the button when i want to hide it with the hidesBottomBarWhenPushed.
Though its not working, i tried everything but the button wont show up.
[self.tabBarController addSubview:button];
[self.tabBar addSubview:button];
[self.tabBarController.tabBar addSubview:button];
none of the above is showing my button
Great sample.
Perhaps I’m misunderstanding the behavior of the center button but it doesn’t seem like it selects a new view – it doesn’t highlight and it seems more like a usual button with some action?
I’m using Storyboards and it would be very helpful if this sample could be ‘updated’ to use the Storyboard instead.
Ole,
I have created the project using Storyboard and fixing the issue where the center button wasn’t switching to its related controller.
Cheers
Here is how I solved this very same problem using custom segues in iOS 5. There is also a pre-storyboard demo project that I think is much simpler than this example but I guess that is not for me to say I am bias :). I would appreciate any feedback incase I am missing something!
Check it out here http://www.scott-sherwood.com/?p=777
Hi Scott,
Nice tutorial, thank you. I’d like to see the https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar demo using a Stroryboard. Instead of completely customizing the UITabBar, I would like to see how the UIButton (+) actually performs the transition to the controller pointed to by the segue.
I cannot seem to find a way to connect the segue to the button. Any help would be appreciated. Thanks!
[…] I’m following the example on how to create a tab bar with a center button like Path,Instagram, etc from here: http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/ […]
Scott, while your demo project works fine, it doesn’t seem so solve Ole’s problem (which is exactly my problem as well.)
The main issue is that we don’t want to have a custom UITabBar. We want a custom UITabBarItem (the raised + button in the middle of the UITabBar). The problem I face is that I cannot find a way to trigger the segue action from the raised button because it’s added dynamically and I haven’t found a way to connect the button to the segue.
As Ole said, it would be awesome to see the https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar demo be updated so that the raised button triggers the segue as if it has been the real UITabBarItem it replaces.
Hi Peter, thanks for the tutorial very useful. However, i have an issue, I’d appreciate some help with. I have tried in many ways to load child views from the custom tab bar controllers through code with luck, I also tried building a 5 tab TabBarController in IB and made the class for the tabbarcontroller point to your provided raisedtabbar class.. the buttons all pain good, but when I click the different tabs, I don’t see anything but black screen… non of the child views are loading. What am I missing? thanks much Danny
[…] http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/ […]
UITabViewController inside a UINaviagationController? Thought it was the other way round
This is a very good tutorial,helped me alot with my work.
I would like to know something
How can i add actions for each tabbar item?
Could we do this using interface builder? Is it possible to add a button over the tabbarcontroller using interface builder?
[…] Interested in creating a custom center button for your app? Here’s a link to a short tutorial, with code (read the comments for some useful details): http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/ […]
In my app I am making my app to tabbarcontroller by clicking a button in viewcontroller I want to add a UIButton at the place of Third tabbar button,how to do that? I have followed this tutorial(may be the best)-but not getting an idea
I am creating the tabbar like this
In ViewController.h
@property (strong,nonatomic) IBOutlet UIViewController *myhomeVC,*groupVC,*uploadVC;
@property (nonatomic,strong) NSMutableArray *Array;
@property (strong,nonatomic) IBOutlet UINavigationController *homeNavBar,*groupNavBar,*uploadNavBar;
In ViewController.m
-(IBAction)Login:(id)sender{
Array = [[NSMutableArray alloc] initWithCapacity:5];
myhomeVC = [[FirstViewController alloc] initWithNibName:@”FirstViewController” bundle:nil];
homeNavBar=[[UINavigationController alloc]initWithRootViewController:myhomeVC];
homeNavBar.tabBarItem.title=@”First”;
groupVC = [[SecondViewController alloc] initWithNibName:@”SecondViewController” bundle:nil];
groupNavBar=[[UINavigationController alloc]initWithRootViewController:groupVC];
groupNavBar.tabBarItem.title=@”Second”;
uploadVC = [[ThirdViewController alloc] initWithNibName:@”ThirdViewController” bundle:nil];
uploadNavBar=[[UINavigationController alloc]initWithRootViewController:uploadVC];
uploadNavBar.tabBarItem.title=@”Third”;
[Array addObject:homeNavBar];
[Array addObject:groupNavBar];
[Array addObject:uploadNavBar];
appDelegate.tabBarController.viewControllers = localViewControllersArray;
[self.parentViewController.view setHidden:YES];
appDelegate.window.rootViewController = appDelegate.tabBarController;
}
}
[…] 看看这篇。它解释了是怎么做的。 http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/ 回复duduxiong1983: […]