Tutorial: Custom iPhone tabbar using Appcelerator Titanium

by Sam on 02/13/2011


While working on v2 of the Endeavour iPhone app, I was faced with a need to create a custom tab bar, this seemed a much easier task when using titanium compared to Obj-C! I actually ended up writing a library that is available on the netsells github which I will show you how to use in this tutorial.

The basic logic behind is all is to hide the existing tab bar (but keep it there for switching windows) and overlay where it should have been with a window containing buttons. Below are the steps you should take to create something shown to create the following

First off, we need some custom images, I’ve quickly made the following in photoshop (icky green, I know) to use in this example (I’m only doing this for the non-retina screen, adding support for retina should be as simple as adding @2x).


[Icons by Joseph Wain]

Next we need to get the library into the project, my project folder is stuck on my desktop so I did the following

cd ~/Desktop/testTabApp/Resources
git clone git@github.com:netsells/customTabBar.git

After git has done it’s thing you should be able to call the customTabBar library in your app.js.

For the example app show at the beginning of this post, I replaced the contents of app.js with:

// Create the tab group
var tabGroup = Titanium.UI.createTabGroup();

// Assign windows & tabs
// IMPORTANT:
// 'tabBarHidden: true' should be set on all windows
// height should be set to 480 - customTabBar's height
// (change 480 to app screen height)
var win1 = Titanium.UI.createWindow({
title:'Tab 1', height: 440,
tabBarHidden: true, backgroundColor: '#111' });
var tab1 = Titanium.UI.createTab({ window:win1 });

var win2 = Titanium.UI.createWindow({
title:'Tab 2', height: 440,
tabBarHidden: true, backgroundColor: '#999' });
var tab2 = Titanium.UI.createTab({ window:win2 });

var win3 = Titanium.UI.createWindow({
title:'Tab 3', height: 440,
tabBarHidden: true, backgroundColor: '#AAA' });
var tab3 = Titanium.UI.createTab({ window:win3 });

var win4 = Titanium.UI.createWindow({
title:'Tab 4', height: 440,
tabBarHidden: true, backgroundColor: '#FFF' });
var tab4 = Titanium.UI.createTab({ window:win4 });

// Add them to the group
tabGroup.addTab(tab1);
tabGroup.addTab(tab2);
tabGroup.addTab(tab3);
tabGroup.addTab(tab4);

// open tab group
tabGroup.open();

// Here is the magic
Ti.include("customTabBar/customTabBar.js");

var myCustomTabBar = new CustomTabBar({
tabBar: tabGroup,
imagePath: 'iphone/images/',
width: 80,
height: 40,
items: [
{ image: 'home.png', selected: 'home_over.png' },
{ image: 'cloud.png', selected: 'cloud_over.png' },
{ image: 'cart.png', selected: 'cart_over.png' },
{ image: 'settings.png', selected: 'settings_over.png' }
]
});

As you can see, I’ve created a standard tabbar, told each window to not show it, then created an instance of the CustomTabBar class and fed it with my settings. If I were to run the app in the simulator, I get the following (woop!):

Finally, if you find yourself in need of hiding the newly created tab bar.. (and then showing it…)

myCustomTabBar.hide(); // Hide the tab bar

// Show after 5 seconds
setTimeout(function() {
myCustomTabBar.show();
}, 5000);

Hope this helps anyone looking to create a tabbar! Please let me know if you use this in any projects as I love my stuff being used! :)

There are 40 comments in this article:

  1. 02/26/2011Steffen says:

    Nice solution. Just one thing. When you reset the Tabs it throws an error:

    [code]
    [ERROR] invalid image type. expected either TiBlob or TiFile, was: NSNull in -[TiUIImageView setImage_:] (TiUIImageView.m:679)
    [/code]

    I just removed the function “resetTabs” or the line “tabBarItems[i].image = null;”.
    It still works, the “old” tab bar is just beneath…

  2. 02/26/2011sam says:

    Yeah, I know about this. Titanium doesn’t offer a way to remove the current image, this is the best way I’ve found – although it does throw a nasty error :(

  3. 03/14/2011Gui says:

    GitHub repo seems empty…

  4. 03/14/2011sam says:

    Sorry about that, try again :) https://github.com/netsells/customTabBar

  5. 03/17/2011Gui says:

    Is it supposed to work under Android ?

  6. 03/17/2011sam says:

    I haven’t tried it on Android and didn’t have it in mind when I was creating it. But I don’t see why it wouldn’t work to be honest :)

  7. 03/18/2011Gui says:

    Unfortunately it seems it doesn’t work on Android; nothing is displayed. It turns out that there a lot of differenices in the way bars behave in Android and iOS, even with Titanium.

  8. 04/15/2011Gregg says:

    I found a way to fix the error

    Replace
    tabBarItems[i].image = null;

    With
    tabBarItems[i].image = ‘images/clear.png’;

    and put a transparent png called clear.png in your iamges folder

  9. 05/3/2011Chandra says:

    Though this example does not have any IPhone specific code and components displayed are simple Titanium API components, it doesnot work on Android.
    Can someone explain y is it not working on Android Emulator?

  10. 05/6/2011gondo says:

    your blog images doesn’t show :/

  11. 05/6/2011sam says:

    Fixed :)

  12. 05/6/2011sam says:

    Never used android so don’t have a clue I’m afraid!

  13. 05/20/2011Stephan says:

    Awesome! But how do you switch tabs, when linking from a window in one tab to another? tabGroup.setActiveTab(n); will only switch the window, but not the tab. An event listener “open” for each window object will only fire once, while focus will fire the whole time.

  14. 05/20/2011sam says:

    Ah, I didn’t think of that while writing the library! I will add it to my todo list :)

  15. 05/21/2011Stephan says:

    Adding a tabGroup.addEventListener(‘focus’, function(e){ myCustomTabBar.preset(e.index);}); will do the trick. You just have to add the preset function to customTabBar.js that does not contain a tabGroup.setActiveTab(item); or else it will fire the focus again as mentioned above, causing a flickering of the tab image

  16. 05/22/2011sam says:

    https://github.com/netsells/customTabBar/wiki/Todo

  17. 06/1/2011Yann says:

    Hi,

    Thank You for your custom bar!! It’s a really big help for me.

    I had this before return :

    var customTabBarArrow = Ti.UI.createImageView(
    {
    top:-7,
    width:10,
    height:10,
    left:(settings.width/2) – (10/2),
    backgroundImage:’images/arrow.png’
    });

    and, in addEventListener

    var a1 = Titanium.UI.createAnimation();
    a1.left = (pos*settings.width) + (settings.width/2) – (10/2);
    a1.duration = 300;
    a1.curve = Ti.UI.ANIMATION_CURVE_EASE_IN_OUT;
    customTabBarArrow.animate(a1);

    To make an effect like this : http://idevrecipes.com/2010/12/17/twitter-app-tab-bar-animation/

    Enjoy ;)

  18. 06/2/2011john says:

    I am trying to get the tab bar change when we moved to different page. Can any body help on this?

  19. 06/16/2011tyler says:

    I am getting an error in the simulator console when you click one of the tabs.

    [ERROR] invalid image type. expected either TiBlob or TiFile, was: NSNull in -[TiUIImageView setImage_:] (TiUIImageView.m:690)

    Any Clues?

    THanks!

  20. 06/16/2011sam says:

    Can you post your code for me to see? pastebin.com

  21. 06/16/2011tyler says:

    http://pastebin.com/AePNcXq6

    thank you

  22. 06/16/2011sam says:

    I don’t think it can find your images, or the image is a lickle bit corrupt ;)

  23. 06/16/2011tyler says:

    It happens with your images also. I am using the 1.7 SDK.

  24. 06/16/2011tyler says:

    the error occurs when you call the restTabs() function, it doesn’t like how you’re ‘clearing’ the images by assigning NULL to it. Is there any other way around this? Could you just toggle the visibility of the image?

  25. 06/16/2011tyler says:

    Here is the solution:

    replace this:

    tabBarItems[i].image = null;

    with this:

    tabBarItems[i].image = settings.imagePath + settings.items[i].image;

  26. 06/21/2011Jone says:

    Hi Yann
    What a great idea! I’m having trouble implementing it, would you consider pasting the whole code?

  27. 06/21/2011J. says:

    Anyone managed to make this work with retina images? It works in the iPhone 4 simulator, but on the phone the images are missing..

  28. 07/7/2011Ben says:

    Just a quick alteration if you want to be able to completely replace the tab images on click (if for instance you have transparent buttons or one’s that change position slightly). Adding some animation would be the icing on the cake!

    Just add a global variable selected after the tabBarItems initialization like so:
    var tabBarItems = [];
    var selected = -1;

    Then replace your assignClick function as follows:
    var assignClick = function(tabItem) {
    tabItem.addEventListener(‘click’, function(e) {
    // Just fetching the ‘i’ variable from the loop
    var pos = e.source.pos;

    // Reset previous tab image if replacing
    if (selected != -1){
    tabBarItems[selected].backgroundImage = settings.imagePath + settings.items[selected].image;
    }

    // Update selected index
    selected = pos;

    // Switch to the tab associated with the image pressed
    settings.tabBar.tabs[pos].active = true;

    // Reset all the tab images
    resetTabs();

    // Replace tab image?
    tabBarItems[pos].backgroundImage = ‘images/clear.png’;
    // Set the current tab as selected
    tabBarItems[pos].image = settings.imagePath + settings.items[pos].selected;
    });

  29. 07/18/2011Raul Riera says:

    If you are storing your images inside the /iphone folder, there is a bug in Titanium where they won’t be uploaded to the device

  30. 08/2/2011AHoth says:

    hey, is it possible to get this to work in landscape mode?

  31. 08/4/2011Tyler says:

    Hey — this is great!

    I’m running into one issue with this…

    Whenever I open a new window over the main tabGroup that houses the custom Tab Bar, I lose the tab bar when I close the new window. Then if I open that new window again, then close, the tab bar is back. Explicitly opening the tabGroup window via a public method I added doesn’t seem to help. Thoughts?

  32. 08/5/2011Tyler says:

    Answered my own question — the custom tab bar object wasn’t being attached to the tabGroup, so it was not animating with the tab group. Simple fix was to add this to the js include:

    settings.tabBar.add(customTabBar);

    just before this:
    customTabBar.open();

  33. 11/10/2011Chritsian Gonzalez says:

    Hi, First good Tutorial….

    I have a problem i have 4 Tabs i click the Tab 2 and go to windows 2 in this window i have a button when click this button change me to the window 1 but the tab is Focus in the 2 tab i need when click to the first tab the tab change to the first.

    Thanks

  34. 11/10/2011Sam says:

    Chritsian, are there any errors? It mighty be worth you putting logging in the class to see what is happening (it’s very simple)

    - Sam

  35. 11/10/2011Christian Gonzalez says:

    Hi, Sam thanks for responding. But i put the log gin in the class but i don’t find the way to change the windows and the Tab focus.

    Thanks

  36. 11/10/2011Sam says:

    Christian, put your code on pastebin.com and post on here?

  37. 11/10/2011Christian Gonzalez says:

    Sam i put all the Files with images in a zip.

    http://www.fileserve.com/file/ThCPMCW/TabExample.zip

    Thanks for your help…

  38. 11/10/2011Christian Gonzalez says:

    Another problem is i Need hide the tabGroup how make this….???

    Thanks

  39. 11/14/2011Ktiniatros says:

    Thanks a lot for this custom tab bar.

    I would like to inform the android developers that this cannot work for android because of the way android handles windows which do not belong in a tabgroup. It is not possible in android to show a window outside of a tab group and because the custom tab bar is actually a window you cannot show it.

  40. 11/15/2011Ktiniatros says:

    (what I mean is that you cannot have a window opened at the same time with the window of the active tab or any other window in general in android)

Write a comment: