Build a Dynamic Accordion Menu in Flash CS4 with ActionScript 3.0 and XML

by Mario Santos 142

In this tutorial you will learn how to build an accordion style menu from scratch that can be configured by using an external file.

The menu items can be totally configured in XML with label and can load text, image or swf on it’s open “state”. Just follow the tutorial, it’s quite simple. At the end you will see a second example achieved by this procedure.



Final Result

The final result of this tutorial is a fully functional XML configured flash menu that can load Text, Images or SWF files, like this one:

Pre-Requisites

Adobe Photoshop CS 3/4 if you want to customize your menu – You can download free trial here

You will need Flash CS4 (but it will work also in previous versions).

Also need a menu item designed; can be any image, but I recommend to use mine that can be downloaded here, you will find the .psd file also so you can use your own style, but make sure you have the left side with 20px aprox.

Have the TweenLite Engine that can be downloaded here. Normally we did not need this, but i prefer using it than native AS3 tween classes.

You should feel fine about developing in Adobe Flash even if this tutorial is very simple to follow.

Download Source Files

Step 0 – Getting Started

The very first thing is to create a new Action Script 3 Project!

Then make the stage with these dimensions:

Save the file in a folder called menuAccordion with the name “tutorial”.

Step 1 – Create the menu Item

We will need only one menu item, the others we will re-create them from this one. We should do this way because our menu is dynamic, so… how we will do this, simply, we create a movie clip to behave as menu item, then export it to action script use, and then just need to duplicate him in action script.

The first thing to do is to import the image that I’ve made, go to menu File->Import-> Import to stage, this way the image is placed immediately on stage. I’ve used the “itemback1.jpg”:

Now convert it into a MovieClip, right-click on it, Convert to Symbol, and choose MovieClip, name it menuItem (important!), and click export to Action Script (Important), the things should be like the image (my OS is French, but the options are in the same place, should be easy to follow):

The correct names are very important because we will use it in Action Script. If an warning is shown, press ok.

Our menu needs some parts, a Text field to receive the label, then a textarea to display text is the user define it on the XML and a empty MovieClip to load JPG/SWF files, used to display content when menu is open.

Step 2 – Put content loaders in place

I mean, the label for the menu, the text and the empty movie clip:

Edit our recently transformed movie clip (double click on it), create a new layer above the existing, name it label and the first thing is to add a text field on the gray section, write on text: “HOME”, on properties choose dynamic text, with embed characters (important!), align left and single line. Size it according to accordion height and give it a black-gray color.

You cannot see the text HOME? You forgot to embed characters right? Embed the uppercase chars only and name this instance itemLabel!

Create a new layer and name it buttonBack, then draw a rectangle over all the gray area:

Convert this rectangle into a MovieClip, name it buttonBack (do not export for action script) and then name this instance into “buttonBack” and put the alpha to zero, in Style Combobox.

The next thing to do is to create a content loader. Create a new layer and label it contentLoader, next we need to draw a rectangle, according to the image right size:

Transform it in a MovieClip called itemLoader, name the instance name to itemLoader and double click on it and click on the Right-Click on it and select Guide, this apparently will do nothing, but when you go back to the menu is simply disappeared, but that is not 100% true, it is there on the layer but with a transparent background…

Now create a new Layer always on the top of all, and name it text, draw here a text like the image, make it as Dynamic text, center align, and if needed embed characters. Name his instance as itemText.

Well, you menu item is done! Just need now to write the XML file, and make some action script code.

Before, just check if your layers order is like this:

Step 2 – Write the XML

Create a xml file called menu.xml and write this down!:

<?xml version="1.0" encoding="utf-8"?>
  <menu menuOpen="1" moveOnMouseOver="false">
  		 <item Ititle="home" IcontentType="image/swf" IcontentData="image2.jpg"/>
 		 <item Ititle="about" IcontentType="text" IcontentData="Our company is based on UK! Know how we have born!; Click here"/>
  		 <item Ititle="Products" IcontentType="image/swf" IcontentData="image5.jpg"/>
 		 <item Ititle="Services" IcontentType="image/swf" IcontentData="item2.swf"/>
 		 <item Ititle="Contact" IcontentType="image/swf" IcontentData="image1.jpg"/>
  </menu>

The xml structure is quite simple, the menuOpen property will define the menu tab taht will open automatically on start, then the moveOnMouseOver indicates if the menu item should open when the mouse over it’s tab. Then the items, in Ititle we define the label for the menu, will be used in the itemLabel text field, then the type of content (IcontentType) that the menu will load, if its =”text” the itemText text field will load the IcontentData text, or if is “image/swf” the contentLoader will load the IcontentData object url.

Save this file and put also the gs folder of downloaded Tweenlite AS3 into the same folder as the main Flash file (menuAccordion).

Now go back to Flash, on the main stage we got only one menuItem right? right-click on it an choose Cut (CTRL+X), now create a new MovieClip (menu Insert -> New Symbol and name it menuLoader, press ok and then past our menuItem (CTRL+V), the position is not important.

Go back to main stage, open library panel and drag the menuLoader into the first layer, the things are equal, but this time we got a menu loader where the menu items will be loaded. Name this instance menuContainer.

Lets add a new Layer on the stage and name it mask, on it design a rectangle, convert it to a movieclip and name it masker. Name its instance also as masker. Right-Click on that Layer and then Mask it, this mask will be used to avoid the last menu to be shown when we don’t want!

Now, add a third layer on top of those two, name it Actions, go to actions panel and write this down.

//import tweenlite classes
  import gs.TweenLite;
  import gs.easing.*;

  var MENU_ARRAY:Array; //used to save the items data
  var OPENED_MENU:int; //to inform the menu that should be open at startup
  var MOVE_ON_MOUSE_OVER:Boolean=false; //tha name says everything
  var xmlLoader:URLLoader; //the xml loader

loadXML("menu.xml"); //load the xml

function loadXML(Uri:String):void {
  xmlLoader = new URLLoader();
  xmlLoader.addEventListener(Event.COMPLETE, onComplete);
  xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, onError);
  xmlLoader.load(new URLRequest(Uri));
  }

function onError(evt:ErrorEvent):void {
  trace("cannot load xml file");
}

function onComplete(evt:Event):void {
  //read and load xml into array, by parsing it using prepareMenu
  MENU_ARRAY=prepareMenu(xmlLoader.data.toString());
  placeItemsOnStage(); //place all required items on stage.
}

function placeItemsOnStage():void {
	var pos:Number=0;
  //define the container properties
  menuContainer.x=0;
  menuContainer.y=0;

	for(var c:int=0; c<MENU_ARRAY.length; c++) {
	  var it:menuItem = new menuItem; //load out menuItem, because its exported to AS, we can use it here
	  	it.x=c*27; //its the gray border width
  		it.y=0; //place on top
  		it.id="Item-"+c; //id the menuItem
  		it.name="Item-"+c; //name de menuItem
  		it.posX=pos; //actual pos, useful to open and know is position
  		it.itemLabel.text=String(MENU_ARRAY[c].Ititle).toUpperCase(); //load the label in uppercase
  		it.addEventListener(MouseEvent.CLICK, onMouseClick); //add mouse click listener
  		if(MOVE_ON_MOUSE_OVER==true) it.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); //if configured, load the mouse over event
  		it.useHandCursor=true;  //use hand cursor
  		it.buttonMode=true; //buttonMode
  		it.itemText.visible=false; //hide the textField
  		menuContainer.addChild(it); //add the menu item as child

		 if(String(MENU_ARRAY[c].IcontentType)=="image/swf")	{ //check the content and load things accordint to it
		  	var ldr:Loader = new Loader();
	  		ldr.x=27;
			ldr.y=0;
  			it.addChild(ldr);
  			ldr.load(new URLRequest(MENU_ARRAY[c].IcontentData.toString()));
  		}
		else if(String(MENU_ARRAY[c].IcontentType)=="text") {
  			it.itemText.visible=true;
  			it.itemText.text=MENU_ARRAY[c].IcontentData.toString();
  		}
	pos+=27; //the next menuItem x position
  }

 //put mask in place
  masker.width=(MENU_ARRAY.length*27+325)
  masker.height=menuContainer.height;
  masker.x=0;
  masker.y=0;

 moveItem(OPENED_MENU-1); //open menu confirured in XML

}

  function onMouseOver(evt:MouseEvent):void {
  	if(evt.target.name.toString()=="buttonBack") prepareMove(evt)
  }

function prepareMove(evt:MouseEvent):void {
  var targetName:String = evt.currentTarget.name.toString(); //get the menuItem
  var temp:Array = targetName.split("-"); //split his name: Item-x
  var itemNumber:int=(temp[1]); //got item number
  moveItem(itemNumber); //move it
}

function onMouseClick(evt:MouseEvent):void {
  if(evt.target.name.toString()=="buttonBack")  prepareMove(evt); //mouse action was done in buttonBack
  else trace("Item "+evt.currentTarget.name+" clicked!"); //mouse action was made on accordion area
 }

function moveItem(num:int):void {
  var itemToMove:menuItem=menuContainer.getChildByName("Item-"+String(num)) as menuItem;
  //get the menuItem child
  for(var m=0;m<MENU_ARRAY.length;m++) //move one-by-one to the new position
  {
  var tempMc = menuContainer.getChildByName("Item-"+m);
  if(tempMc.x > itemToMove.x) TweenLite.to(tempMc, 1, {x:((tempMc.posX) + itemToMove.width-27), ease:Quart.easeOut}); //see tweenLite for info about this.
  else if(tempMc.x <= itemToMove.x) TweenLite.to(tempMc, 1, {x:(tempMc.posX), ease:Quart.easeOut});
  }
}

function prepareMenu (XMLData:String):Array
  {
  //make sure it cames in XML
  var menuXML:XML = new XML(XMLData);
  //just in case
  menuXML.ignoreWhitespace = true;

  //get XML item's entrys
  var XMLItems = menuXML.descendants("item");

 //load all items into an array
  var itemsArray:Array = new Array();
  var itemObj:Object;
  for(var i in XMLItems)
  {
  itemObj=new Object();
  itemObj.Ititle=XMLItems[i].@Ititle;
  itemObj.IcontentType=XMLItems[i].@IcontentType;
  itemObj.IcontentData=XMLItems[i].@IcontentData;
  itemObj.itemID="menu"+i;
  itemsArray.push(itemObj);
  }
  OPENED_MENU=menuXML.@menuOpen; //get menu for open.
  MOVE_ON_MOUSE_OVER=([email protected]()=="true" ? true : false); //get the option for load or not mouseOver open
  return itemsArray;
}

//finish.
stop();

The code is commented, so read it carefully before perform some actions, after that you just need to have some fun and make your own accordion menus! In the XML you can add, remove and edit accordion labs and items easily.

The last thing we need to do is to double-click the menuContainer / menuLoader and delete the menuItem there, we do not need it here because we will add it as child via AS3. Change the stage height to 200px (it’s the menu height).

One more example:

Hope you like it! You can download the final flash project here. Don’t forget to help us grow, by submitting this article to your favorite social networking using the bellow buttons.


Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>