Flex 4 Vertical Sliding Menu

by David Salahi on July 28, 2010

Right-click to view source.

Here’s a Flex 4 menu component that you can modify with your own menu items and plug in to any application. The menu items are Labels; clicking on one triggers an event which you can handle in the container or elsewhere in your application. This sample menu includes two submenus which slide open and closed as needed. This sliding behavior is controlled by Flex states and uses Flex transitions to smoothly switch from one state to another. Almost all of the code is MXML with only a few lines of ActionScript in event listeners.

Here is the core of the menu:

<s:VGroup paddingBottom="15" paddingLeft="15" paddingRight="15" paddingTop="5" gap="0"> <!-- gap must be 0; see note in CSS file -->
	<s:Label id="home" text="Home" buttonMode="true" click="menuClickHandler(event)" />
 
	<!-- Submenu 1 -->
	<s:Label id="subMenu1" text="Submenu1" buttonMode="true" click="expandSubMenu1(event)"  />
	<s:VGroup id="subMenu1Links" paddingLeft="15" gap="0"
			  alpha.allCollapsed="0" height.allCollapsed="0" 
			  alpha.subMenu2Expanded="0" height.subMenu2Expanded="0"  >
		<s:Label id="subMenu11" text="Submenu 1 Item 1" buttonMode="true" click="menuClickHandler(event)" />
		<s:Label id="subMenu12" text="Submenu 1 Item 2" buttonMode="true" click="menuClickHandler(event)" />
	</s:VGroup>
 
	<!-- Submenu 2 -->
	<s:Label id="subMenu2" text="Submenu 2"  click="expandSubMenu2(event)" buttonMode="true" />
	<s:VGroup id="subMenu2Links" paddingLeft="15"  gap="0"
			  alpha.allCollapsed="0" height.allCollapsed="0" 
			  alpha.subMenu1Expanded="0" height.subMenu1Expanded="0" >
		<s:Label id="subMenu21" text="Submenu 2 Item 1" buttonMode="true" click="menuClickHandler(event)"  />
		<s:Label id="subMenu22" text="Submenu 2 Item 2" buttonMode="true" click="menuClickHandler(event)"  />
	</s:VGroup>
 
	<s:Label id="menuItem2" text="Menu Item 2" buttonMode="true" click="menuClickHandler(event)" />
	<s:Label id="menuItem3" text="Menu Item 3" buttonMode="true" click="menuClickHandler(event)" />
	<s:Label id="menuItem4" text="Menu Item 4" buttonMode="true" click="menuClickHandler(event)" />
	<s:Label id="menuItem5" text="Menu Item 5" buttonMode="true" click="menuClickHandler(event)" />
</s:VGroup>

It is essentially a set of Label objects within a VGroup. Expanding submenus are created by nesting additional VGroups within the main VGroup. Before each submenu VGroup is a Label which causes the submenu VGroup to expand when the Label text is clicked. All Labels which are not submenu headers trigger an event when clicked. All menu item clicks are handled by a single event listener:

protected function menuClickHandler(event:MouseEvent):void
{
	var menuEvent:MenuItemSelectedEvent = new MenuItemSelectedEvent(MenuItemSelectedEvent.MENU_ITEM_SELECTED, event.target.id);
	dispatchEvent(menuEvent);
}

A custom MenuItemSelectedEvent object is created which contains the id of the menu item that was clicked. The new event is then dispatched to the container, MenuTest.mxml. Within the menu component, inside a Metadata block the event is declared so that Flex will expect the menu component to dispatch the specified type of events:

<fx:Metadata>
	[Event(name="menuItemSelected", type="MenuItemSelectedEvent")]		
</fx:Metadata>

This enables the menu container, MenuTest.mxml, to declare an event listener in MXML (see "The Menu Container" section, below).

Menu States

Three states are declared for use with the transitions that occur when the submenus slide open and closed:

<s:states>
	<s:State name="allCollapsed"/>
	<s:State name="subMenu1Expanded"/>
	<s:State name="subMenu2Expanded"/>
</s:states>

For each submenu you have you’ll need one state that defines its expanded appearance. Here’s how one submenu’s appearance is defined:

<s:VGroup id="subMenu1Links" paddingLeft="15" gap="0"
		  alpha.allCollapsed="0" height.allCollapsed="0" 
		  alpha.subMenu2Expanded="0" height.subMenu2Expanded="0"  >

In the allCollapsed state (all submenus closed) the height of the VGroup containing the submenu labels is 0 and its alpha is 0. Similarly, when subMenu2 is expanded subMenu1 has its height and alpha set to 0.

subMenu2 works the same way, only changing the parameter values the opposite way. If you add any submenus you will need to add a new state for each submenu. You will also need to set the height and alpha properties for the new state on the existing submenu VGroup tags.

Transitions Between Menu States

Now that we’ve defined the three states we can set up the effects we want to see when transitioning between them. Here’s the definition of the transition to subMenu1 open:

<s:Transition toState="subMenu1Expanded" >
	<s:Parallel >
		<s:Resize target="{subMenu1Links}" duration="500"  />
		<s:Fade target="{subMenu1Links}"  duration="500" startDelay="250"/>
		<s:Resize target="{subMenu2Links}"/>
		<s:Fade target="{subMenu2Links}" duration="250"/>
	</s:Parallel>
</s:Transition>

We start by creating a Parallel effect so that the four effects within it will all play simultaneously.  Note that no from or to values need be specified here since they are already specified as described above. Flex figures out the from and to values for each effect based on the from/to states and the properties set for each of the various states.

In the snippet above the first Resize effect has as its target the VGroup subMenu1Links which contains the two Labels for subMenu1. The initial state of the menu at startup is allCollapsed (since that’s the first state defined with the <states> block). This means its height is 0. The height of subMenu1Links for the subMenu1Expanded  state is not explicitly defined within its VGroup so its default value is used (100%). From this information, the Resize effect knows that it needs to resize from 0 to 100% during the transition.

Similarly, the subMenu1Links alpha value at startup (allCollapsed) is 0 but is not explicitly defined for the subMenu1Expanded state. Again, its default value (1) is used and the Fade effect takes it from 0 to 1. This fade has a 1/4 second startDelay so that the other Fade effect can complete before this one starts. The second pair of Resize and Fade effects handle fading out and collapsing subMenu2 (if it is expanded—otherwise, they do nothing). I think this combination of timings produces a nice effect but, of course, you can adjust them for a different user experience. The other two transitions, subMenu2Expanded and allCollapsed, are very similar.

The Menu Container

The menu component, VerticalSlidingMenu.mxml, is instantiated within MenuTest.mxml as follows:

<local:VerticalSlidingMenu id="menu" menuItemSelected="menuItemSelectedHandler(event)"/>

An event listener is declared to handle MenuItemSelected events which occur in response to a mouse click. In this example, the listener displays in a label below the menu the id of the menu item which was clicked.

Enhancements

A nice enhancement would be to draw little triangles by the labels to denote the open and closed states of the submenus. Another enhancement could be to draw a background behind each label so that each menu item appears to be within a box or other shape, perhaps with a gradient background, for example.

Update 7/29/10

See my post Flex Vertical Sliding Menu, Part II for code to highlight the currently active menu item.

Get the Menu Source Code

Download the Flex 4 Menu Component project or right-click on the SWF above to view source.

{ 7 comments… read them below or add one }

sganza November 16, 2010 at 3:20 pm

Hello, great job!!!
How can I dynamically load menu element?
Tks

Jeannie January 5, 2011 at 6:35 pm

I would also be interested in Tks answer. I am using your fabulous VerticalSllidingMenu. It works beautifully. However my swf is too large.

How can I load the menu with moduleLoader to keep overall swf size low?

David Salahi January 6, 2011 at 4:07 am

You could build the menu as a separate Flex module and then load it dynamically at run-time. For details on how to do this I’d recommend chapter 7 of the book Enterprise Development with Flex by Yakov Fain, Victor Rasputnis, Anatole Tartakovsky.

However, it probably only makes sense to do that if your menu is not an integral part of your site. I.e., if your menu is just used on some subset of screens and is not used on the opening screen it could make sense to defer loading until after the main app is loaded. But if your menu is used on every page there’s probably no advantage to separating out the menu. In the latter case, your app needs the menu in order to be useful.

And, I haven’t checked but I’d guess that the menu alone would be pretty small anyway. But your mileage may vary :)

Dave

Student February 4, 2011 at 10:09 pm

Hello.I want to use this component in my own website(but I am working on this website)
I use flex 4 version and I have tested this example .But I receive error about MenuItemSelectedEvent.I can’t this component.
I don’t understand what is MenuItemSelectedEvent in here?can anybody explain datail me?

David Salahi February 5, 2011 at 4:03 am

Student,
MenuItemSelectedEvent is a class that is included with the downloadable project. When the menu is clicked it dispatches one of these events to tell the listener which menu item is clicked.

What kind of error are you getting?
David Salahi

Student February 5, 2011 at 7:33 am

Thank you for help me, David Salahi.Before I can’t find full source code of this example .Already I have found project.Thanks.

Miguel Lemos October 23, 2012 at 6:55 pm

Excelent!

Leave a Comment

 

{ 2 trackbacks }

Previous post:

Next post: