Following on from the recent post about automatically closing the open branches of the Tree control when you open a new branch; this is a slicker implementation that does the same thing but allows you to keep the animation. Currently the Flex control falls over if you try and animate multiple branches opening or closing.
The main thing to point out here is that this example also works if you click the Tree disclosure icon (the little triangle) as well as the item. Most of the examples out there in the blogosphere that show you how to click on items to open branches forget that the disclosure button will open/close the branch and ignore the itemClick handler you’ve setup.
I listen for the itemOpening and itemClick events and pass on to a method called handleSelectedItem. This method then checks the depth of the selected item like so.
-
var d:int = TreeListData(TreeItemRenderer(tree.itemToItemRenderer(selectedItem)).listData).depth;
This looks crazy but you need to grab the itemRenderer’s listData property to find the depth of the object. It’s quite convoluted but you can grab the renderer with the Tree’s itemToItemRenderer method, cast it to the default TreeItemRenderer class and cast the listData property to the default TreeListData class to get the depth property off that … phew!
We need the depth because I only want to work with the root level branches which is level 1 in the case of a Tree. I then cycle through the Tree’s dataprovider which gives me the items in my XMLListCollection. These will correspond to the root level items as they are XML nodes with all of the children nodes (branches) in them. I can then look for siblings to the selected item using the getRoot method and close any open siblings.
-
if(tree.isItemOpen(i) && i!=selectedItem && idepth==1 && isSibling)
-
{
-
tree.addEventListener(TreeEvent.ITEM_CLOSE,itemClosed);
-
tree.expandItem(i,false,true,true); // CLOSE SIBLING
-
openInstantly = false;
-
}
I create an eventListener to listen for when the open root level branch is closed and because there will ever only be one branch closing I can use animation. The openInstantly Boolean prevents the selectedItem from opening … yet. When the closed item has finished I run a short Timer delay to make sure the animation listeners are all cleared and then open the selected item.
Here’s the Application class:
-
<?xml version="1.0" encoding="utf-8"?>
-
<mx:Application
-
-
xmlns:mx="http://www.adobe.com/2006/mxml"
-
layout="absolute"
-
width="200"
-
height="300"
-
>
-
-
<mx:Script>
-
-
<![CDATA[
-
-
import mx.controls.treeClasses.TreeItemRenderer;
-
import org.osflash.thunderbolt.Logger;
-
import com.criticalmass.gucci.homepage.renderers.CustomTreeItemRenderer;
-
import mx.controls.listClasses.IListItemRenderer;
-
import mx.controls.treeClasses.TreeListData;
-
-
import mx.collections.XMLListCollection;
-
import mx.events.TreeEvent;
-
import mx.controls.Tree;
-
import mx.events.ListEvent;
-
-
private var dpx:XML = <nav>
-
-
<node label="Womens">
-
<node label="Flora by Gucci" url="assets/swf/movies/flora.swf" />
-
<node label="Gucci by Gucci" url="assets/swf/movies/gucci.swf" />
-
<node label="Classics" url="assets/swf/movies/classics.swf" >
-
<node label="Classic 1" url="http://gucci.com/class/classic1.html" />
-
<node label="Classic 2" url="http://gucci.com/class/classic1.html" />
-
<node label="Classic 3" url="http://gucci.com/class/classic1.html" />
-
</node>
-
</node>
-
-
<node label="Mens">
-
<node label="Pour Homme" url="assets/swf/movies/ph.swf" >
-
<node label="Pour Homme 1" url="http://gucci.com/ph/classic1.html" />
-
<node label="Pour Homme 2" url="http://gucci.com/ph/classic2.html" />
-
</node>
-
</node>
-
-
<node label="Boys">
-
<node label="Pour Homme" url="assets/swf/movies/ph.swf" >
-
<node label="Pour Homme 1" url="http://gucci.com/ph/classic1.html" />
-
<node label="Pour Homme 2" url="http://gucci.com/ph/classic2.html" />
-
</node>
-
</node>
-
-
</nav>;
-
-
private var dp:XMLListCollection = new XMLListCollection(dpx.children());
-
-
private var selectedItem:Object;
-
-
private var timeDelay:Timer;
-
-
//-----------------------------------------------------------------------------------
-
private function treeItemOpening(e:TreeEvent):void
-
{
-
if(!tree.isItemOpen(e.item))
-
{
-
selectedItem = e.item;
-
handleSelectedItem();
-
}
-
}
-
//-----------------------------------------------------------------------------------
-
private function treeItemClick(e:ListEvent):void
-
{
-
selectedItem = Tree(e.currentTarget).selectedItem;
-
handleSelectedItem();
-
}
-
-
//-----------------------------------------------------------------------------------
-
private function handleSelectedItem():void
-
{
-
-
var openItems:Array = tree.openItems as Array;
-
var openInstantly:Boolean = true;
-
-
var d:int = TreeListData(TreeItemRenderer(tree.itemToItemRenderer(selectedItem)).listData).depth;
-
-
if(tree.dataDescriptor.isBranch(selectedItem))
-
{
-
for each (var i:Object in tree.dataProvider)
-
{
-
var idepth:int = TreeListData(TreeItemRenderer(tree.itemToItemRenderer(i)).listData).depth;
-
var isSibling:Boolean = XML(getRoot(i)).@label != XML(getRoot(selectedItem)).@label;
-
if(tree.isItemOpen(i) && i!=selectedItem && idepth==1 && isSibling)
-
{
-
tree.addEventListener(TreeEvent.ITEM_CLOSE,itemClosed);
-
tree.expandItem(i,false,true,true); // CLOSE SIBLING
-
openInstantly = false;
-
}
-
}
-
-
if(openInstantly) tree.expandItem(selectedItem,!tree.isItemOpen(selectedItem),true,false);
-
}
-
else
-
{
-
// Clicked on an item -- DO STUFF!
-
}
-
}
-
-
//-----------------------------------------------------------------------------------
-
/*
-
Function for accessing the Root item of the Tree
-
*/
-
private function getRoot(childObj:Object):Object
-
{
-
var parentObj:Object = tree.getParentItem(childObj);
-
if(parentObj != null) return getRoot(parentObj);
-
else return childObj;
-
}
-
-
//-----------------------------------------------------------------------------------
-
/*
-
Item closed handler
-
*/
-
private function itemClosed(e:TreeEvent):void
-
{
-
tree.removeEventListener(TreeEvent.ITEM_CLOSE,itemClosed);
-
-
timeDelay = new Timer(200,1);
-
timeDelay.addEventListener(TimerEvent.TIMER_COMPLETE,openSelectedItem);
-
timeDelay.start();
-
}
-
//-----------------------------------------------------------------------------------
-
private function openSelectedItem(e:TimerEvent):void
-
{
-
timeDelay.removeEventListener(TimerEvent.TIMER_COMPLETE,openSelectedItem);
-
if(selectedItem) tree.expandItem(selectedItem,true,true,false);
-
}
-
]]>
-
</mx:Script>
-
-
<mx:Tree
-
-
id="tree"
-
width="200"
-
height="300"
-
dataProvider="{dp}"
-
labelField="@label"
-
itemClick="treeItemClick(event)"
-
itemOpening="treeItemOpening(event)"
-
/>
-
-
</mx:Application>


Recent Comments