Recently I’ve noticed that in iOS, the navigation animation for the title bar is more than simply slide in new screen from right to left, despite I’m using iPhone for few months now, I didn’t aware of the animation until I felt something different with the animation done by Sencha Touch, the attention paid to the detail made the whole screen switching much smoother.

Your browser does not support native video tag, that’s bad
(video quality might not be that clear, but still able to see the title bar animation)

It appears that Sencha Touch 2 provide a new component Ext.navigation.View, which according to the documentation, it’s a container with extra features. Using navigation view is a bit different than what I’ve done previously.

Another navigation animation I found different from iOS native and Sencha Touch is the tab panel switching, in Sencha Touch, it use the slide effects, while in stock apps in iOS, it don’t have animation, but this one is a quick fix in Sencha Touch.

So, as usual, we need the MVC folder structure, index.html, app.js and Viewport.js to get started. In this testing, I’m using tab panel on the viewport.

app/view/Viewport.js

Ext.define('SenchaNavigation.view.Viewport', {  
  extend: 'Ext.tab.Panel',  
  config: {  
    tabBarPosition: 'bottom',  
    fullscreen: true,  
    layout: 'card', //adding this will disable the slide animation  
    items: [ { xtype: 'homepanel'} , { xtype: 'aboutpanel'} ]  
  }  
});

As I mentioned, quick fix for tab panel animation, without the setting the layout: 'card', by default it has the slide animation, setting it will disable the animation. Here I added 2 view into the viewport.

app/view/Home.js

Ext.define('SenchaNavigation.view.Home', {  
  extend: 'Ext.navigation.View',  
  xtype: 'homepanel',  
  config: {  
    title: 'Home',  
    iconCls: 'home',  
    navigationBar: {  
      items: [  
        {  
          xtype: 'button',  
          text: 'Editor',  
          align: 'right'  
        }  
      ]  
    }, 
    items: [{ title: 'Home' }]  
  }  
});

In the Home panel, there are some new things, first, I extend Ext.navigation.View, then the navigationBar config item. In Ext.navigation, it has View and Bar, but from the documentation, we know that the bar is private, so we’ll use the navigationBar config to set the title bar.

The idea here is the tab panel, which is the Viewport in this case, will have Home view, and About view, in the Home view, there is a button, when tapped, it will show the editor screen, the editor screen does not cover up the tab panel like my previous project, this is what I wanted to achieve, to feel more native (I still have no clue about Android’s standard GUI, as I did not expose to Android much).

So all of the view will share the single navigation view, which is helping to push and pop views (switching views). Since the Home panel is the main screen, so I added a default button “Editor” on right corner of the title bar, and since the navigation view will get the title from the items, so I just add an items with the title “Home”, also note that I did not use toolbar in the first tab panel, as I’ll be using the navigation view which came with the toolbar, but for the About tab panel, I will be using a toolbar.

app/view/About.js

Ext.define('SenchaNavigation.view.About', {  
  extend: 'Ext.Panel',  
  xtype: 'aboutpanel',  
  config: {  
    title: 'About',  
    iconCls: 'settings',  
    items: [  
      {  
        xtype: 'toolbar',  
        title: 'About'  
      },  
      { html: 'About Panel' }  
    ]  
  }  
});

Nothing special in the About view.

app/view/Editor.js

Ext.define('SenchaNavigation.view.Editor', {  
  extend: 'Ext.Panel',  
  xtype: 'editorpanel',  
  config: {  
    title: 'Editor',  
    items: [{ html: 'Editor!' }]  
  }  
});

Plain normal editor view that do nothing. Now the only part in this example is the controller, which is busying with handling the view switching and button hiding (views sharing same toolbar, so button will be shared as well).

app/controller/Main.js

Ext.define('SenchaNavigation.controller.Main', {  
  extend: 'Ext.app.Controller',  
  config: {  
    refs: {  
      homePanel: 'homepanel',  
      editorPanel: 'editorpanel',  
      editButton: 'homepanel > container > container > button[text="Editor"]'  
    },  
    control: {  
      homePanel: {  
        push: 'onPush',  
        pop: 'onPop'  
      }, 
      editButton: {  
        tap: 'onEditCommand'
      }  
    }  
  },  
  //more events here  
});

This is the skeleton of the controller, which defining the view and button, and also events. For the editButton, I’m using the query selector (something like CSS selector) to locate the editor button in the homepanel (remember homepanel is the xtype for Home view), as for the two container, I have to figure it out from the webkit debugger tools, after that I select the button which contains the text “Editor”, I also can do ‘homepanel > button’ here, but if there is other button, they will probably affected by this selector.

Now on the control, since the home panel is extending navigation view, so it naturally have extra function and events, pop and push, which is the event for pushing in new views for display and pop out a view for hiding, we’ll need to listen to these two events for displaying the “Editor” button. As for the editButton tap event, I just simply trigger the even onEditCommand in this controller. Note that on last project I use initialize event in the view to handle the toolbar button event, and then use fireEvent from the view to the controller, this is just another way of doing that, and it’s cleaner.

app/controller/Main.js – more events

onEditCommand: function() {  
  if (!this.editorPanel) {
    editorPanel = Ext.widget('editorpanel');  
  }

  this.getHomePanel().push(this.getEditorPanel());  
}

This event is fired when the editor button is tap, here I use a if to check for the editorPanel, which I defined in the refs, because the editorPanel is undefined at this moment, so I just use the Ext.widget to get the view object, and then just call the push of the home panel, and the smooth animation will happen automagically.

app/controller/Main.js – more events

onPush: function(view, item) {  
  var editButton = this.getEditButton();

  if (item.xtype === 'editorpanel') {  
    this.getEditButton().hide();  
  } else {
    this.getEditButton().show();
  }
},  
onPop: function(view, item) {  
  if (item.xtype === 'editorpanel') {  
    this.getEditButton().show();  
  } else {
    this.getEditButton().hide();  
  }
}

These two events is basically doing the opposite thing, for the onPush event, obviously I need to get the reference to the edit button first, and then, I check if the active item is editor panel, if it is editor panel, then the editor button will be hidden, vise versa. Then on the onPop event, I also check for the editor panel, because it means which view is being popping out (removing), so since it’s the editor panel that being remove, so I show the edit button.

And did I mention that the Back button is generated for free? Nice!

Source code: https://github.com/stephensaw/Sencha-Navigation