If you are a Flex developer, one of the Flex components you will work on quite a bit is the Flex List control. This entry will hopefully help you when creating custom List renderers the (hopefully) right and much lighter way. Almost all the Flex applications I work on require a List thats skinned a little differently and display more information than that could be represented by a label value.
There are quite a number of examples on the web on creating the a custom renderer for a List control. Very simply, a custom renderer can be used as a List renderer by calling it as below:
So thats simple enough. However most of the code I have seen that is used to create custom renderers starts with a parent Canvas tag or some other container. This works for the most part and hides some of the complexity of creating custom renderers, however Canvas and other containers are pretty heavy objects to have a lot of in memory, especially when you are using a bunch of lists in the application. We ran into this issue on the Fan for example when we played fullscreen video without destroying our multiple List instances. As you can see in the image below, the Fan uses three Lists and one TileList in the square view. So at any point we could have close to 40 renderers displaying data.
So how do you create lighter renderers? well here’s how:
1) Implement IListItemRenderer:
Lists expect the renderers to implement the IListItemRenderer interface. Conveniently, the UIComponent class implements most of the methods mandated by the interface (I will not go into my ‘God Object’ rant about the UIComponent class here). The only method you *have* to implement is the get/set data functions to make it compliant with the IDataRenderer interface that IListItemRenderer extends.
2) Implement IDropInListItemRenderer:
So now you have a List renderer that works for the most part. You may consider leaving it at this point but you are still missing some magic. For one thing, your renderer isn’t really aware of its position, etc in the List. To get that info, your renderer must implement the IDropInListItemRenderer interface which forces another couple of getters and setters: those for accepting the BaseListData object. When the List creates instances of your custom renderer and when it swaps data in and out of your renderer, it will pass it the BaseListData object. This object will tell your renderer its row/column index and its the owner List object. So now your renderer is much more aware of its position in the world.
3) Create UITextFields:
Most Lists have textual data that they represent. Text and Label components would seem to be the obvious choice for showing that data. However, these are much heavy objects again. UIComponents, unlike containers, have no qualms about what kind of children they can add to their displaylist (Containers only let classes extending UIComponent to be added to them. Sprites etc can only be added to their rawChildren list). So you can very easily add simple native TextField instances and size them appropriately. However styling them is tedious. Instead, consider adding UITextField instances. These play nice with the Flex LayoutManager and can also use the CSS styles in the Flex app by just being assigned the styleName property.
4) Set styles:
Like HTML, its always a good idea to keep style declarations in external CSS files. These can usually be assigned to Flex controls by just setting their styleName property. For example you can create a Flex CSS file and create a unique identifier like this:
To style a list with the styles you declare above, all you need to do is:
[xml] …. [/xml]
What is a less obvious is that you can create arbitrary values in the style declaration (These aren’t compiled to a packed actionscript object the way a class would be but more like a dynamic class would be). So in my earlier style declaration, I could just as easily add:
A List by default would have no idea what to do with the myawesometextstyleName style value and would ignore it. However, the CSSStyleDeclaration object referenced by the List is passed by reference to the renderers as well. So in your updateDisplayList function, you can call getStyle(‘myawesometextstyleName’) and get the value declared there. Now by assigning the value to the UITextField, you can get the formatting you are looking for.
We still have some ways to go. The remaining stuff comes in next entry so stay tuned :).