Flex 4.5 Mobile Development – Tabs on Top

June 14, 2011By 25 Comments

The Flex 4.5 TabbedViewNavigatorApplication for mobile development includes a set of tab buttons at the bottom of the screen by default, such as:

However, there may be times when you prefer to have your tabs at the top of your screen instead. This post shows how this can be done quickly. The steps I need to take are:

1) Find and copy the TabbedViewNavigatorSkin.as class into your mobile project in a folder called skins. On my Mac, I can find this skin class here (using the Flash Builder 4.5.1 latest prerelease version): /Applications/Adobe Flash Builder 4.5/sdks/4.5.1/frameworks/projects/mobiletheme/src/spark/skins/mobile/TabbedViewNavigatorSkin.as. If you’re using Flash Builder 4.5, just look under the ../sdks/4.5/frameworks/projects/mobiletheme/src/spark/skins folder.

2) Set your CSS style to use this skin class either in your main application file like below or in your external stylesheet:

<fx:Style>
		@namespace s "library://ns.adobe.com/flex/spark";
		s|TabbedViewNavigator 
		{
			skinClass: ClassReference("skins.TabbedViewNavigatorSkin");
		}
</fx:Style>

3) In your TabbedViewNavigatorSkin class, change the package at the top of the class to reflect your local skins folder instead, so replace the first package line from package spark.skins.mobile to package skins

4) Scroll to the bottom of the skin class to the layoutContents() function. This is where the tab bar and content layout is done. The content in this case referes to the children of your View classes, such as my UI components and results List in my application.

    override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.layoutContents(unscaledWidth, unscaledHeight);
        
        var tabBarHeight:Number = 0; 
        
        if (tabBar.includeInLayout)
        {
            tabBarHeight = Math.min(tabBar.getPreferredBoundsHeight(), unscaledHeight);
            tabBar.setLayoutBoundsSize(unscaledWidth, tabBarHeight);
            tabBar.setLayoutBoundsPosition(0, unscaledHeight - tabBarHeight);
            tabBarHeight = tabBar.getLayoutBoundsHeight(); 
            
            // backgroundAlpha is not a declared style on ButtonBar
            // TabbedViewNavigatorButtonBarSkin implements for overlay support
            var backgroundAlpha:Number = (_isOverlay) ? 0.75 : 1;
            tabBar.setStyle("backgroundAlpha", backgroundAlpha);
        }
        
        if (contentGroup.includeInLayout)
        {
            var contentGroupHeight:Number = (_isOverlay) ? unscaledHeight : Math.max(unscaledHeight - tabBarHeight, 0);
            contentGroup.setLayoutBoundsSize(unscaledWidth, contentGroupHeight);
            contentGroup.setLayoutBoundsPosition(0, 0);
        }
    }

The tabBar.setLayoutBoundsPosition(x,y) function is the key here, and if you modify the code to set the position of the y variable to 0, it will be placed at the top of the application:

        if (tabBar.includeInLayout)
        {
            tabBarHeight = Math.min(tabBar.getPreferredBoundsHeight(), unscaledHeight);
            tabBar.setLayoutBoundsSize(unscaledWidth, tabBarHeight);
            tabBar.setLayoutBoundsPosition(0,0);
            tabBarHeight = tabBar.getLayoutBoundsHeight(); 
            
            // backgroundAlpha is not a declared style on ButtonBar
            // TabbedViewNavigatorButtonBarSkin implements for overlay support
            var backgroundAlpha:Number = (_isOverlay) ? 0.75 : 1;
            tabBar.setStyle("backgroundAlpha", backgroundAlpha);
        }
        if (contentGroup.includeInLayout)
        {
            var contentGroupHeight:Number = (_isOverlay) ? unscaledHeight : Math.max(unscaledHeight - tabBarHeight, 0);
            contentGroup.setLayoutBoundsSize(unscaledWidth, contentGroupHeight);
            contentGroup.setLayoutBoundsPosition(0, 0);
        }

There are a couple other things to note here. Simply setting that one line to 0 will put the tabs on top, but the content group (including the actionBar if it’s visible property is true), also had layout bounds position starting at 0 on the Y axis, meaning the tabs will now cover some of your content, so we need to also change the contentGroup.setLayoutBoundsPosition(0,0) to contentGroup.setLayoutBoundsPosition(0, tabBarHeight);. The tabBarHeight is already calculated for us, so we just need to change 0 to that variable and our content will start right after the tabs. Here’s the result:

Now if I want to get rid of my ActionBar in favor of screen space, I just need to go into my View classes and set actionBarVisible to false. For instance, something like:

<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" title="Search Location..." actionBarVisible="false" xmlns:json="com.adobe.serialization.json.*" >

Final Result:

Filed in: Flash Builder 4.5Flex 4.5Flex 4.5/MobileFlex MobileUncategorized Tags:

About the Author ()

Comments (25)

Trackback URL | Comments RSS Feed

Sites That Link to this Post

  1. Weekly Developer Journal : June 12 – June 18 | June 19, 2011
  1. Greg Wilson says:

    This is a test

  2. Greg Wilson says:

    Another test

  3. Hari Krishna says:

    thanks Holly, very helpful…

  4. Babak says:

    Hi guys
    I was wondering if you had any experience with developing a Flex application for IOS that records voice and plays it on Ipad 2 ?

    If any one has any idea about how to do this please give me a hint.

    many thanks in advance.

    Cheers

  5. Vincent says:

    very useful

  6. Richard R says:

    Doesn’t moving the tabs to the top violate Apple’s UI development Guidelines?

    I think it does, and I’d venture a guess that it could lead to your app not receiving App Store approval.

    Don’t know for sure though, so this is entirely speculation.

  7. Simon Davies says:

    I have a question about tabs, I would like to create 3 tabs at the bottom of my application, but where as the middle one will always open up a menu page say I would simply live the left and right tabs to be previous and next buttons, so I will need to change the view/page of each next/previous links when navigating onto a different page each time.

    Any idea how to with tabbed based application, or not so will have to create three square buttons at the bottom to mimic tabs?

    hope this makes sense!
    thanks

  8. Davyt says:

    Hi,

    I just wanted to ask, I notice in this post you have an application that is using the GPS on the phone to find the users location and then bring up restaurants based on that location.

    I am really trying hard to do something very similar to this atm and wondered if you could help me in finding resources or materials detailing how this can be achieved?

    Thanks for the help :-)

  9. Vivek Giri says:

    Hi Holly,

    when I am trying to put the following code in my tabbed mobile application

    @namespace s “library://ns.adobe.com/flex/spark”;
    s|TabbedViewNavigator
    {
    skinClass: ClassReference(“skins.TabbedViewNavigatorSkin”);
    }

    I ma getting an error the explanation about the error is .
    Multiple markers at this line:
    -1120: Access of undefined property TabbedViewNavigatorSkin.
    -1172: Definition skins:TabbedViewNavigatorSkin could not be found.

    what could be the possible reason I have copied the TabbedViewNavigatorSkin.as into a folder called skins .

    • Hi Vivek, is your skins folder under your src folder? You should be able to see a Flash Builder helper drop down when you start typing into that ClassReference definitions, (after typing skins.) that will give you suggestions on available classes. If you don’t see it in there then you will get this error and you likely have it in a different place.

      Hope that helps!
      Holly

  10. Bobby Edge says:

    Is there a way to put the TabbedViewNavigator under the ActionBar at the top?

  11. Pascal says:

    Holly,

    First, thanks a lot for all the valuable tips on your blog: great developer resource :-)

    Could you please update this post for FB 4.6?

    Indeed I would like to have an Android styled mobile app (tab on top) and the possibility to switch Title bar visibility (TitleBar which will be placed at the bottom of the screen)

    Thanks beforehand,

    Pascal

  12. Pascal says:

    To move the TitleBar, use the same kind of trick with spark.skins.mobile.ViewNavigatorSkin.

  13. Primo says:

    I am just wondering how to have a fixed size of the ButtonBarButton on a TabBar.

    Similar to this image below link:
    http://dl.dropbox.com/u/20329917/tab.png

  14. Bernardo says:

    i have a question..

    how can i do that m y view menu always visible ?

  15. Zaur says:

    That’s great but in my case I want to place both bottom and top tab bars on a single view, how can I do this?

    • Zaur says:

      Voila! I’ve done this..thanx for your post!

      • Zaur says:

        Mmm looks like something more tricky… why assigning I’ve created two TabbedViewNavigators in a View and assigned skinClass=”skins.TabbedViewNavigatorSkin” to one of them but when I run it it displays only one of the TabbedViewNavigators (bottom one)…But if I delete the bottom one tab and assign the same skinClass to TabbedViewNavigator it works pretty well displaying that tab bar on top… What’s the problem here & how can i solve this?

  16. Thanks, this was really useful – I used this quick tip in Flex 4.6.

  17. Stan M says:

    Is it possible to place ViewMenu at the top of the screen?

    PS: Thanks for the great blog!

Leave a Reply