Starter Step

Posts Tagged ‘tabstrip

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);


  • 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