UINavigationController implementation for SenchaTouch

SenchaTouch is web development framework for building native-looking mobile apps (iOS & Android) using standards-based web technologies such as HTML5 & CSS3. The Sencha website features several very impressive demos. However, the framework is still in beta and many useful features are either incomplete or missing entirely.

One common interaction in iPhone applications is multi-level navigation which places a back button in the toolbar and allows the user to drill down into the data. In a native app, the UINavigationController class manages this hierarchy of views and asks the currently selected view information about itself for display. For example, the current view may have a navigationTitle of “Tier 1” and its child view may have a navigationTitle of “Tier 2.” UINavigationViewController will inspect these views and make sure the correct title is visible in the navigation bar according to the currently selected view. See the diagram below:

Navigation_interface

SenchaTouch has something similar with the NestedList class which shows a hierarchy of Ext.List panels. However, it would be nice to have something much more generic that allows any type of panel to be placed in the hierarchy. Below this post is the source code for PanelStack which functions much like UINavigationController. Each panel in the stack can push more panels beneath it or pop itself off the stack (identical to pressing the back button). Additionally, each panel is has an animation property which is run on push and reversed on pop making interactions such as flipping a card over to see its back and then returning to the front very easy to accomplish.

How to use PanelStack

var bottomLevel = new Ext.Panel({ title: "Start page" });
var firstLevel  = new Ext.Panel({ title: "Tier 1" });
var secondLevel = new Ext.Panel({ title: "Tier 2" });

var controller  = new PanelStack({ items: [bottomLevel] });
// Showing the bottomLevel, a title of "Start page" and no back button

controller.pushPanel(firstLevel);
// Showing the firstLevel, a title of "Tier 1" and a "back" button

controller.pushPanel(secondLevel);
// Showing the secondLevel, a title of "Tier 2" and a "back" button

controller.popPanel();
// Showing the firstLevel, a title of "Tier 1" and a "back" button

// Manually tapping the "back" button
// Showing the bottomLevel, a title of "Start page" and no back button

The current code for the class is below.

PanelStack = Ext.extend(Ext.Panel, {
  scroll:    false,
  layout:    "card",
  animation: "slide",
  backButton: null,
  toolbar:    null,
  hideToolbarOnFirstPage: false,
  
  initComponent: function() {
    this.backButton = Ext.apply({}, this.backButton || {}, {
      text:    'Back',
      ui:      'back',
      handler: this.onBackTap,
      scope:   this,
      hidden:  true
    });
    this.backButton = new Ext.Button(this.backButton);
 
    this.toolbar = Ext.apply({}, this.toolbar || {}, {
      dock:    'top',
      xtype:   'toolbar',
      cls: (this.hideToolbarOnFirstPage) ? "hidden" : "",
      items: []
    });
    this.toolbar.items.unshift(this.backButton);
    this.toolbar = new Ext.Toolbar(this.toolbar);
    
    this.dockedItems = this.dockedItems || [];
    this.dockedItems.push(this.toolbar);
    
    PanelStack.superclass.initComponent.call(this);
  },
  
  popPanel: function() {
    var oldItem = this.items.last();
    this.items.remove(oldItem);
    
    var newItem = this.items.last();
                
    this.setCard(newItem, { type: oldItem.pushedAnimation, reverse: true });
    
    if (this.items.length <= 1) {
      this.backButton.hide();
      
      if (this.hideToolbarOnFirstPage) {
        this.toolbar.el.addClass("hidden");
      }
    }
    
    if (newItem.navigationTitle) {
      this.toolbar.setTitle(newItem.navigationTitle);
    }
  },
  
  pushPanel: function(panel, anim) {
    anim = anim || this.animation;
    
    var me = this;
    panel.pushedAnimation = anim;
    panel.pushPanel = function(panel, anim) { return me.pushPanel(panel, anim); };
    panel.popPanel = function() { return me.popPanel(); };
    
    this.items.add(panel);
    this.setCard(panel, anim);
    this.backButton.show();
    this.toolbar.el.removeClass("hidden");
    if (panel.navigationTitle) {
      this.toolbar.setTitle(panel.navigationTitle);
    }
  },
 
  onBackTap : function() {
    this.popPanel();
  }
});
About

Second Story creates enchanting, informative, and entertaining media experiences with innovative technologies that empower connections to ideas.

Tagged with: , , , ,
Posted in Design