MHTabBarController – A custom tab bar for iOS 5 using the new container APIs

Creating your own container view controllers, i.e. view controllers that can contain other view controllers, used to be a pain but now iOS 5 makes it a lot easier.

Especially for iPad apps that is great, because all of that screen space means you probably want to divide it up amongst more than one view controller.

Today I was messing around with these new container APIs and built my own tab bar controller. It works just like a regular UITabBarController, except the tabs look quite different and the pages slide in and out of the screen with a nice animation.

Screenshot of MHTabBarController in the demo app
If you want to learn more about how to do this, then check out the source code or get the iOS 5 by Tutorials ebook. It has a full chapter on these new view controller containment APIs, plus twenty or so other chapters on more iOS 5 goodness!

Comments

  1. valshebnik says:

    Thanks for sharing Matthijs, it looks pretty interesting. BTW I think it’s a good practice to write some useful stuff to strengthen and polish the gained knowledge :]
    A few questions regarding the source code.
    - What the “\file” marker in header comment block is for?
    - Why are you using floorf() function in MHTabBarController.m, line 44 and later?
    - Is there any _practical_ reason to explicitly specify float type of literals?
    And I have to admit your code is very readable. Could you please write a post about code readability, maybe some not so obvious rules people could keep in mind while writing code.

  2. Matthijs says:

    Hi valshebnik,

    1) The \file marker is for the Doxygen documentation generation tool.

    2) I use floorf() to round the number to the nearest integer (rounding down always). This is necessary to prevent the image from being placed in between two pixels, for example at pixel 36.5, which will make it blurry.

    3) By putting the “f” behind a number you tell the compiler it is a float instead of a double (or integer). It probably doesn’t make much difference in practice, though.

  3. valshebnik says:

    2) Good point! Never thought about that. Will do the same from now on. 3) I noticed many times folks are doing the same, but I haven’t found any practical meaning in that yet. Was hoping you spill some light on it as always :]
    Thanks for the answers.

  4. Jesper says:

    Re #3: iDevices (starting with the 3GS, iirc) handle floats much faster than doubles. You likely won’t notice any difference most of the time though.

    I tend to denote my numbers with “f” as well (unless I specifically need double accuracy). It doesn’t cost anything at the very least. :)

  5. Alexander Kholodov says:

    Good idea, any reason you’re not releasing the memory?
    dealloc doesn’t exist, viewDidUnload method is losing pointers, instead of releasing the memory

  6. Matthijs says:

    @Alexander This is written for iOS 5 and therefore uses ARC. The cool thing about ARC is that you no longer have to worry about memory management, it is done automatically for you now.

  7. Karlo says:

    Do you know if this have been used in an app the has been approved?

  8. Matthijs says:

    I don’t know. Do you have a reason to believe your app won’t be approved if you use this?

  9. Karlo says:

    No, not at all. Just wondering. It seems alright to me. Thanks for the good work.

  10. Chris Anderson says:

    Great tutorial but how would I add an image to the tab buttons?

    In addTabButtons you do…

    [button setTitle:viewController.title forState:UIControlStateNormal];

    Which is fine because every ViewController has a title.
    The way the native TabBarController works is the child view controller might do something like…

    self.tabBarItem.title = @”Tab 1″;
    self.tabBarItem.image = @”Image 1″;

    I don’t really understand how that’s working (under the bonnet) – can you offer any advice?

    Before you say “just use the native tab bar controller” – I would if I could.

    I have some specific requirements that I don’t think the native one will do?
    e.g.:
    I need the tabs at the top of the screen (not the bottom).
    I need the tabs right aligned not centred.

    Any pointers would be appreciated, thanks.

  11. Matthijs says:

    @Chris Anderson: The tabs are UIButtons, so you can put any image you want on them but you’ll have to modify the MHTabBarController code for this, specifically the selectTabButton and deselectTabButton methods.

  12. Soniya says:

    Thanks for your great work. I customize the view to the view I need and it works fine. What i need to know how we can push a viewcontroller on 1 tab or alleast can able to show modalviewcontroller on 1 tab.

    To be more clear, suppose in tab1 there is a viewcontroller with a button, on clicking button i need to open a new controller but it must open in same contentView and on dismissing it we can go to previous view. right now on present new modalviewcontroller it hide our tab and fill whole screen

    Thanks in advance

  13. Soniya says:

    I get my answer by my own:

    by adding navigationController as a viewController will work just like we do in UITabbarController.

    Thanks sir, I learn from your code how we can create any control by ourselves just we need to increase our scope of thinking and programming

  14. Ricardo says:

    Hello!

    Does that controller work with Storyboards? I mean, if I see it in the Storyboard desk.

    Thanks.

  15. Matthijs says:

    @Ricardo The storyboard editor doesn’t support custom view controllers such as this. You’ll be able to drop a plain View Controller into the storyboard and set its Class to MHTabBarController, but you can’t do anything else with it.

  16. Brian says:

    Whats the easiest way hide and reshow the tabbar. I have a login screen the user need to access first then gain access to the tabbar and items.

  17. Matthijs says:

    @Brian The best way to do that is to show the login screen modally on top of the one with the tab bar.

  18. John says:

    If I want to add “HeaderView” on top of TabBar Button.
    Which part of the code in MHTabBarController that I can modify?
    Currently, if just add header subview on top of TabBar, I can not tap on the TabBar button

  19. Ian Stallings says:

    Is there a way to use this container within another container? I thought it might be possible if I added the API methods to MHTabController class (didMoveToParentViewController, willMoveToParentViewController) then added it to my rootViewController using presentViewController but it blew up on me. I’m still working through it but I was wondering if you’ve tried this and solved it?

  20. Matthijs says:

    @Ian I don’t see why it wouldn’t work, but you don’t use presentViewController for that. Instead, you use addChildViewController:. See the docs for UIViewController for more examples.

  21. Ian Stallings says:

    Sorry I misspoke. I did add it using addChildViewController but it blows up when the presentViewController is called. I think it should work but I obviously have something fudged.

  22. Ian Stallings says:

    Also I wanted to say thank you for the example! All I could find up to this point was the WDC video about how to create a UIViewController container class.

  23. Jerry Carter says:

    Bug report: The application does not respond to touch events in iOS 6.0 on the iPad in landscape mode.

    Interestingly they work in portrait mode and will work in landscape if you rotate to portrait and back to landscape. If also works if you press the 1x / 2x button.

  24. Angel says:

    If anyone is interested, I just made some changes to allow further customization. With my changes, you can set the tabbar, contenview and selection indicator directly from IB, which allows you to completely change the layout. Also, colors and images have been added to the customization to provide an easy way to change this properties without modifying the code.

    You can see the pull request at https://github.com/hollance/MHTabBarController/pull/6 or directly download the code from my fork at https://github.com/angelolloqui/MHTabBarController

    Hope it helps!

  25. Jerry Carter says:

    The bug that I reported has been acknowledged by Apple as issue #12478980. It is currently open.

  26. Richard says:

    I was able to replicate by using the same code as you. But what if I wanted to do this on a view by view basis. Different primary tabs for each view. I’m using a slider navigation for another portion. I feel like I am completely missing something here.

  27. tony says:

    Is there anyway to present a modal view right under the same tab without present a new full screen full as default?
    which mean if I tab on anything under tab1, a modal view can present under the same tab1 ? Currently if I present madal view, it will show the new view in full screen which also cover the tab controller

  28. Anil M N says:

    how to make the tabbar position to below the navigation bar..

Leave a Reply

Your email address is required but will not be visible to others.

 *
 *