Starter Step

TabStrip for Titanium Mobile

Posted on: February 28, 2011

Another UI component we found missing in Titanium Mobile was a TabStrip, like the one you would find in Facebook’s Three20 project for the iPhone where you can have as many tabs as you like and have them fit nicely on the top of the screen because they are scrollable.

After spending some time we came up with a solution that we believe works really well. It takes in any number of labels and will dynamically size the horizontal scroll width and provide arrow indicators that more tabs exist in either direction. Just pass in an onselect function and you can get the tab index for a selected tab – with this you can change the data on the screen. The code below uses the days of the week as an example and will swap out the table view’s data based on the tab selected.

function createTabStrip(options) {
 options = options || {};
 params = {
   labels: options.labels || [],
   onselect: options.onselect || null,
   top: options.top || .1,
   height: options.height || 40,
   backgroundColor: options.backgroundColor || '#000',
   gradientColor: options.gradientColor || '#444',
   selectedColor: options.selectedColor || '#fff',
   unselectedColor: options.unselectedColor || '#999',
   fontSize: options.fontSize || 14
 }

 var labelViews = [];
 var lastSelectedLabel = null;
 var totalWidth = 0;

 var containerView = Titanium.UI.createView({
   top:params.top,
   height:params.height,
   width:320,
   backgroundColor:params.backgroundColor,
   backgroundGradient: {
     type:'linear',
     colors:[
       {color:params.gradientColor,position:0.0},
       {color:params.backgroundColor,position:0.50},
       {color:params.gradientColor,position:1.0}
     ]
   }
 });

 var leftArrow = Ti.UI.createLabel({
   text:String.fromCharCode(171),
   font:{fontSize:params.height / 2,fontWeight:'bold'},
   color:params.selectedColor,
   height:params.height,
   width:15,
   top:params.top,
   left:2,
   textAlign:'left',
   visible:false
 });
 containerView.add(leftArrow);

 var scrollView = Titanium.UI.createScrollView({
   layout:'horizontal',
   top:params.top,
   left:17,
   height:params.height,
   width:286
 });
 containerView.add(scrollView);

 var rightArrow = Ti.UI.createLabel({
   text:String.fromCharCode(187),
   font:{fontSize:params.height / 2,fontWeight:'bold'},
   color:params.selectedColor,
   height:params.height,
   width:15,
   top:params.top,
   right:2,
   textAlign:'right',
   visible:false
 });
 containerView.add(rightArrow);

 scrollView.addEventListener('scroll', function(e) {
   leftArrow.visible = e.x > 5;
   rightArrow.visible = e.x < scrollView.contentWidth - scrollView.width;
 });

 containerView.labels = function(labels) {
   params.labels = labels;
   resetLabels();
 }

 containerView.selectTab = function(index) {
   select(labelViews[index]);
 }

 function resetLabels() {
   totalWidth = 0;
   labelViews = [];
   var oldLabels = scrollView.children;
   if (oldLabels) {
     for (var i = 0,count = oldLabels.length; i < count; i++) {
       scrollView.remove(oldLabels[i]);
     }
   }

   var labels = params.labels;
   for (var i = 0,count = labels.length; i < count; i++) {
      var button = createButton(labels[i], i);
      scrollView.add(button);
   }
   scrollView.contentWidth = totalWidth;
   rightArrow.visible = totalWidth > scrollView.width;
 }

 function createButton(title, index) {
   var buttonView = Ti.UI.createView({
     top:params.top,
     height:params.height
   });

   var label = Ti.UI.createLabel({
     text:title,
     font:{fontSize:params.fontSize,fontStyle:'bold'},
     width:'auto',
     textAlign:'center',
     height:params.height,
     touchEnabled:false
   });
   label.index = index;
   labelViews.push(label);
   buttonView.add(label);
   showAsUnSlected(label);
   buttonView.addEventListener('click', function(e) {
     select(e.source.children[0]);
   });
   buttonView.width = label.size.width + 20;
   totalWidth += buttonView.width;

   if (index == 0) {
     showAsSelected(label);
   }
   return buttonView;
 }

 function select(label) {
   if (lastSelectedLabel) {
     showAsUnSlected(lastSelectedLabel);
   }
   showAsSelected(label)
   if (params.onselect) {
     params.onselect(label.index);
   }
 }

 function showAsSelected(label) {
   label.color = params.selectedColor;
   label.getParent().borderWidth = 1;
   lastSelectedLabel = label;
 }

 function showAsUnSlected(label) {
   label.color = params.unselectedColor;
   label.getParent().borderWidth = 0;
 }

 resetLabels();
 return containerView;
}


var tableData = [
 [{title:'Monday Data'}],
 [{title:'Tuesday Data'}],
 [{title:'Wednesday Data'}],
 [{title:'Thursday Data'}],
 [{title:'Friday Data'}],
 [{title:'Saturday Data'}],
 [{title:'Sunday Data'}]
];

var window = Titanium.UI.createWindow({
 fullscreen:false,
 backgroundColor:'#fff',
 title:'TabStrip'
});

var tabStripView = createTabStrip({
 labels:['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
 onselect: function(index) {
    //This is so you don't get flickering
    tableView.hide();
    tableView.setData(tableData[index]);
    setTimeout(function() {
        tableView.show();
    }, 300);
 }
});

window.add(tabStripView);

var tableView = Ti.UI.createTableView({
 top:tabStripView.height
});
window.add(tableView);

var navGroup = Ti.UI.iPhone.createNavigationGroup({
 window:window
});

var main = Ti.UI.createWindow();
main.add(navGroup);
main.open();

tabStripView.selectTab(0);
Advertisements

9 Responses to "TabStrip for Titanium Mobile"

Hi,

Thanks for the great instructions. Hope you can help me on this: On some of my pages I would like to have the tabstrip (included on the specific pages I choose) I don’t want a table view but just the bar (like a menubar) Should/can I use Ti.include(“tabstrip.js”); ??

After that I would like to accomplish that when someone clicks on Monday that this links to monday.js and click on wednesday it links to wednesday.js

Hope you can help me and I am shure that a lot of people would like to know how to code this.

Thanks in advance,
Danny

Yes I would probably just wrap the createTapStrip function in a js file so you can call it from anywhere and add to any window or view.

Also it’s up to you how you handle the onselect – this code used a table view as an example. So you could always do something like:

onselect: function(index) {
var w = Ti.UI.createWindow({
url:’monday.js’,
top:80
});
w.open();
}

Of course you would want to dynamically determine the actual js file to use by the index, so maybe just store those values in an array.

Hi Brian,

Thanks for taking time on answering my question. If you have some spare time I would love to see some example.
If you don’t have time that’s no problem at all.

Best regards Danny

Hi.

Does it works on Android??

I believe it only work on iPone because of the line 192

Ti.UI.iPhone.createNavigationGroup

Hey man, just wanted to say your a life-saver. I’ve been playing for hours with the Kitchen Sink’s scrolling toolbar, and nothing clicked with my app until I implemented your code. Again, thanks a billion.

Hi Brian,
Thanks a ton for the code. I am trying a similar thing on that also works on Android.

Thanks a ton for the code briann,, life safer 🙂

buttonView.width = label.size.width + 20; on line 123 doesn’t seem to work on android, at least for me. Is there a fix around this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


  • Dave: I can tell you're a ruby guy because you forgot the 'return' keyword. Thanks for the tip though!
  • Chandrashekhar H M: Hi, Thanks its working fine in iOS 6 but not in iOS 7.0. Any Suggestion on this.
  • Coeur: To change a rootViewController, without all this TVNavigationController : myNewRoot = [[UIViewController alloc] init]; myNavigationController.view
%d bloggers like this: