Tag Cloud

Spark TreeList

Did a little bit of vanilla Flex work recently, and I needed a Tree component to display an object hierarchy. Everyone, by now, hopefully knows that mx:DataGrid and mx:Tree are two of the crappiest, bug ridden, worst performing components from Flex 3. And, everyone by now, has left the buggy world of Flex 3 behind and entered the world Flex 4 and the vastly improved Spark components. With the arrival of Flex 4.5 this summer, Adobe finally gave us a rewritten Spark-based DataGrid. Alas, no updated Tree yet, so I had to write my own. So once again, I turned to the trusty combo of List plus custom ItemRenderer to make pure-Spark custom TreeList component that doesn’t suck.

Alex Harui is the guru of turning a Flex 4 Spark List into a look-alike for the old Flex 3 component using skins and a custom ItemRenderer. Alex has used List + ItemRenderer to make a DataGrid, DateField, ColorPicker, Menu + MenuBar, and even an XML-based TreeList. Unfortunately, Alex’s TreeList assumes incoming XML, and I needed a TreeList that could display a simple object hierarchy (root node with children, and those children have children, etc.). Since I couldn’t find exactly what I wanted, I decided to build it myself.

Flattener

The key step to getting a hierarchy of objects to display as a list is: flatten the list, duh! Or at least flatten the part of the tree you wish to display. So, I built a simple adapter class that turns an object hierarchy into an ArrayList that can be given directly to a List‘s dataProvider.

There’s really not much to it. When instantiated with a root object, the object hierarchy is walked recursively to build a flattened list of all the open nodes. Once the initial list is built, openItem() can be called to open a node, and add all its children to the list. Alternately, closeItem() can be called to close a node, and remove all its children from the list.

Design

I used some basic styling and skinning, but the ItemRenderer does the majority of the work. Here’s the abbreviated version of MyObjRenderer.mxml with all the boring stuff edited out:

Each rendered item has a background Rect and a Label. But most importantly, each row has either a ToggleButton (if the object has children) or some non-interactive visuals (if the object doesn’t have children it just gets a dot). The toggle button is the key interactive element used to open or close the node, everything else is part of the visual gravy added to make the list look good.

Focusing on the functional stuff, if you look in the script block, you’ll see two functions: a data() setter and a toggleHandler() to handle toggle button clicks. As expected, clicking the toggle button calls openItem() or closeItem() on the flattener adapter which adds or removes children from the flattened list, respectively. The setter mostly sets up the local variables, but it notably computes if the object has children or not, and also sets the initial state of the toggle button.

Conclusion

With just a little effort, we can have a nice usable Spark TreeList component that looks decent. More importantly, we have total control and can make the TreeList look like anything our designer can throw at us. As is always the case, the combo of List + ItemRenderer proves to be awesome. I tried to cover all the interesting pieces, but for the details, you’ll need to check out the source code.

But here’s one strategy: when you call openItem() add the children to the list, but also set a flag (justOpened=true), then in the itemRenderer you can use the flag to slowly grow the height. Similarly, for closeItem()…

Good luck.

Jason

2.1.2013

6

Thank you, very useful! Is there a way to auto scroll to the bottom of the just opened item? For items that expand beyond the bottom of the list, I have to scroll down, open the next item, scroll down, open the next item, scroll down, etc. Gets very tedious.