Flex item renderers, an expandable list with transitions

I think that each flex developer at a certain point have had the necessity to work with custom item renderers in order to display data in a fancy way.
There is a lot of knowledge around the web regarding this topic but I want to show the process that has driven me to a list that contains custom item renderers with different states and with transitions between each state.
In order to perform this task I’ll show to you how you can create a simple item render, an item renderer with two different states, an item render with some transitions with a visual bug (it’s the default rendering of the list) and one without any bug.
I know that an expandable list can be done also with a VBox and Repeater and that it perform nicely but the list has a caching procedure of the item renderers that is very useful when you have to render on the screen a great number of complex renderers.

A simple item render
Imagine the simple scenario in which your layout require something more than a label in a list and you need to add for instance a “buy now” button, you can create an MXML component

The dataprovider is an ArrayCollection that contain several Article value objects, the class that define an article can be summarized with the following UML diagram

A multi state item render
Imagine now the scenario in which an item renderer needs to show some data and expand itself in order to display on the screen more information about this item, first of all create an MXML component that extends the VBox and that contain three different states, in the first one the component have to show the article name and a button to expand the content

in the second state the component needs to render the price of the article, a “buy now” button and a control in order to expand the third state

In the third state the component has to render the details of the article

In order to complete this task you can define the UI of the component with the following MXML using the <mx:states> tag to define states, label and event handler

If you come back to the list and set this component as an item renderer you will see that the nested states are not rendered, you have to define the List as a variable row list

Now the list is able to render the nested states but if you scroll up and down the list you will see that the states and the data of each item renderer are not consistent with your model, this is due to the List behavior that recycle components in order to render data, when items scroll out of view, its itemRenderer will be moved to the bottom of the list.
In order to keep state and data consistent you have to perform some changes in your code, first of all my suggestion is to create a class that can hold state information and data of each item (in this way also if you work with remote value object you don’t need to make any change on the server side), the class can be summarized with the following UML diagram

the state property contains a string that represent the currentState of the component, the renderData property represents the data you need to display in the components.
Inside your component override the public data method in order to be sure that each time the data changes (each time the list is scrolled) the UI elements are updated

Please not that in the method the article value object has been extracted from the object used to define the data of each item.
In order to keep track of the state of each item render override the currentState method and store the value of the new state in the model

Now is the time to handle the state value in the commitProperties protected method

The List component needs to know the dimension of the item render in order to gracefully adapt each item to its state, this is the reason why in the measure() method you have to explicitly set the values of the properties measuredHeight and measuredMinHeight for each state

If you compile your application now the item renders display the data and the states in a consistent way.

A multi state item render with transitions
In order to add a transition between each state of the your item renderer add the following MXML tags to the previous component and save it with a different name

If you try now the list with this item renderer you’ll be surprised, the transitions don’t perform very well because the item renderer doesn’t know anything about the state in the data method so use an event handler for the StateChangeEvent.CURRENT_STATE_CHANGE event

and store a specific int value in the opened property of each value object.
In the overridden data method add a switch case to handle this value

Now your item renderer is able to handle state and transitions but you’ll see that scrolling the List when it has to render again an item each transition is rendered with a delay, this is due to the live cycle of the List that calls a last udpateDisplayList after a while, in order to solve this stuff you have to put your hands inside the List source code and create an easy reusable class for the item render.

A smart multi state item render with transitions
Surfing the web I found a nice article on item renderers but when I read this sentence “I think a resizing itemRenderer is too complex and not really worth the effort. I believe there is a better way to do this using VBox and Repeater. However, the catch with Repeater is that every child will be created. If you have 1000 records and use a Repeater, you will get 1000 instances of your itemRenderer.” my mind started to think to a solution because with a great number of instances of a complex item renderer the performance of each Flex application can be seriously impacted.
I started to read the source code of the List and I found the two methods that recycle or create the item renderers in the list

In order to avoid the delay I need to change the state of each item renderer in these two methods, the first issues I found are that the transitions defined in the item renderer stop to work and that the height is not rendered.
The other issue I found is that without a base class each time I would like to use smart item renderers in my List I have to start over.
The solution I found is create a VariableRowList  class that extends the List, define a base class for item renderers (I started with a class for VBox based item renderers), define an interface that define a method to use in order to update the state and the height and define the effects I need outside the <mx:tranisitions> tag.
The VariableRowList  class makes an override of the methods used in order to create and recycle the item renderers and attempt to call the method defined in the interface ISmartRenderer the renderer needs in order to handle its state and its height at the end of each method

The ExpandableVBoxRenderer class first of all implements two interfaces, IDropInListItemRenderer and ISmartRenderer, and define a constant that hold an array of objects used to define the heights for each state

In the constructor of this class you find the definition of a listener for the StateChangeEvent.CURRENT_STATE_CHANGE  and for the FlexEvent.CREATION_COMPLETE events and the policy for the scroll bars

The override of the data method use a protected method populateControl() that use the data stored in the  renderData property of the SmartRenderData class in order to populate the UI elements (this method is empty and need to be overridden from the classes that extend the ExpandableVBoxRenderer)

In the override of the measure method the class calculates the needed height trough a private method that get the data from the STATES_HEIGHT constant

The updateState method defined in the ISmartRenderer interface update the state and the height of the component and call the measure method

If you want now start to use this stuffs define the namespace you need to use the VariableRowList   class in your application and place these tags in place of the List you have used before

Define now a new class that extends the ExpandableVBoxRenderer and use it as the base class for a new MXML component that will have the same tags of the one you defined in order to handle the transitions except for the transitions that will be removed and that will be substituted from the following effects

Came back in the class and define the public members that point to the controls defined via MXML

Override the populateControls() method in order to render the data inside the item renderer

and define the handlers for the click event on the buttons in order to play the effect defined trough MXML (see in the source of the sample application to check the other handlers)

In this way your List will be able to render the data and the transition like a charm, check the sample application and the source code (right click, view source) in order to read the complete implementation.

Resources
http://www.returnundefined.com/2006/10/item-renderers-in-datagrids-a-primer-for-predictable-behavior

http://blogs.adobe.com/aharui/item_renderers/

http://flexdiary.blogspot.com/2007/11/order-of-events-for-itemrenderers.html

http://www.adobe.com/devnet/flex/articles/itemrenderers_pt4_print.html

Comments

comments

4 Responses to “Flex item renderers, an expandable list with transitions”
  1. Jorge Bucaran January 18, 2009
  2. bopMoiniSot January 20, 2009
  3. Jeremy Savoy November 5, 2009
  4. Jeremy Savoy November 5, 2009

Leave a Reply

Your email address will not be published.


*