Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium


Appcelerator: Making an expandable (accordian) menu

Published on
4,991 Points
1 Endorsement
Last Modified:
Preface: This article is part of a series focused on cross platform mobile app development (specifically Android and iOS) using the Alloy framework and Titanium Studio made by Appcelerator. This article presumes a working knowledge of Titanium Studio and the Alloy framework.

The Alloy framework has great built in elements for making a simple menu, mainly using the TableView (and TableViewRow) system. Unfortunately this does not include any built in functionality for expanding and collapsing rows. At first glance, using the "insertRowAfter" and "deleteRow" methods of the TableView would work for this. Unfortunately there seems to be a bug with the iOS implementation which leads to a "no row found for index" error when deleting rows. To avoid this error, the menu can be implemented as verticaly aligned View elements.

In the menu View elements represent each row. The rows for the submenus start out "hidden" by a wrapper View with a height of 0. Each row of them menu that does not expand will have a "menuAction" property which will be harvested by the "menuClick" onClick listener. The parent row of each submenu will have extra properties which define how big the submenu is and the name of the submenu's wrapper View.

Example Alloy markup would look like this:

file: /views/index.xml
  <Window class="container">
    <ScrollView id="menu" layout="vertical">
      <View class="menuDivider"/>
      <View class="menuRow" onClick="menuClick" menuAction="home">
        <Label class="rowName">Home</Label>
      <View class="menuDivider"/>
      <View class="menuRow" onClick="menuClick" menuAction="away">
        <Label class="rowName">Away</Label>
      <View class="menuDivider"/>		
      <View class="menuRow" onClick="menuExpand" menuItems="3" submenuId="submenuBrowsers" expanded="false">
        <Label class="rowName">Browsers</Label>
        <Label class="expandArrow" id="expandIndicator" text=">"/>
      <View class="submenuWrap" id="submenuBrowsers" layout="vertical">
        <View class="menuDivider"/>
        <View class="submenuRow" onClick="menuClick" menuAction="chrome">
          <Label class="rowName">Chrome</Label>
        <View class="menuDivider"/>
        <View class="submenuRow" onClick="menuClick" menuAction="firefox">
          <Label class="rowName">FireFox</Label>
        <View class="menuDivider"/>
        <View class="submenuRow" onClick="menuClick" menuAction="ie">
          <Label class="rowName">Internet Explorer</Label>
      <View class="menuDivider"/>
      <View class="menuRow"  onClick="menuExpand" menuItems="4" submenuId="submenuPhones" id="network" expanded="false">
        <Label class="rowName">Smart Phones</Label>
        <Label class="expandArrow" id="expandIndicator" text=">"/>
      <View class="submenuWrap" id="submenuPhones" layout="vertical">
        <View class="menuDivider"/>
        <View class="submenuRow" onClick="menuClick" menuAction="android">
          <Label class="rowName">Android</Label>
        <View class="menuDivider"/>
        <View class="submenuRow" onClick="menuClick" menuAction="blackberry">
          <Label class="rowName">Blackberry</Label>	
        <View class="menuDivider"/>
        <View class="submenuRow" onClick="menuClick" menuAction="iphone">
          <Label class="rowName">iPhone</Label>
        <View class="menuDivider"/>
        <View class="submenuRow" onClick="menuClick" menuAction="windows">
          <Label class="rowName">Windows</Label>
      <View class="menuDivider"/>
      <View class="menuRow" onClick="menuClick" menuAction="settings" id="bottom">
        <Label class="rowName">Settings</Label>

Open in new window

The "tss" (Titanium Style Sheet) file specifies the initial styles of the menu. Note the "submenuWrap" has a height of "0" and visible set to "false". Each submenu row is configured to have a height of "36".
file: /styles/index.tss
".container" : {
   backgroundColor: "#63666a"
"#menu" : {
   backgroundColor: "#63666a",
"Label" : {
   color: "#fff",
   height: Ti.UI.FILL,
   touchEnabled: "false"
".menuDivider" : {
   width: Ti.UI.FILL,
   height: '1dp',
   backgroundColor: '#999'
".menuRow" : {
   height: '40dp',
   backgroundColor: '#777',
   width: Ti.UI.FILL
".rowName" : {
   left: '20dp'
".expandArrow" : {
   right: '20dp'
".submenuWrap" : {
   height: '0dp',
   visible: 'false'
".submenuRow" : {
   height: '36dp',
   backgroundColor: '#888'

Open in new window

The controller is where the expanding and collapsing is processed. When a submenu's title row is clicked, the "expandMenu" function will calculate how tall to make the submenuWrap View so that the submenu will be visible. To collapse the menu the submenuWrap is set back to a height of "0". Note: Each row in the menu includes a "divider" which is a height:1 View, hence why the value used to calculate the new height is 37 for each row instead of 36.
file: /controllers/index.js
function menuClick(e) {
   //  Perform processing based on the menuAction of the clicked menu item

var submenuRowHeight = 37;

function menuExpand(e) {
   var menuRow = e.source;
   var submenuWrap = $[menuRow.submenuId];
   if (menuRow.expanded == 'false') {
      var newHeight = (submenuRowHeight * menuRow.menuItems);
      menuRow.expanded = 'true';
   } else if (menuRow.expanded == 'true') {
      menuRow.expanded = 'false';


Open in new window

This is a basic example of a menu that includes optional expanded submenus created in the Alloy framework that will work for both Android and iPhone devices. The nested submenu items could also be have their own submenus allowing for deeper navigation. By incorporating this menu into an app it can be utilzied as a "side swipe" drawer, options list, or any number of uses.
Author:Mark Olsen

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

Join & Write a Comment

Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Other articles by this author

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month