24 November 2008
To benefit most from this article, it is best if you are familiar with Flex Builder and ActionScript 3.0.
Beginning
If you are displaying a large number of itemRenderers — either in the DataGrid or AdvancedDataGrid — your application's performance may be adversely affected if you do not code these itemRenderers efficiently. Here are some tips that might help:
This series includes the following articles:
Here's an itemRenderer which switches components depending on the value of the data field.
<mx:Canvas>
<mx:Script><![CDATA private function lessThanZero() : Boolean {
return data.price < 0; }
]]></mx:Script>
<mx:Label text="{data.price}" color="#FF0000" visible="{lessThanZero()}" />
<mx:Label text="{data.price}" color="#00FF00" visible="{!lessThanZero()}" />
</mx:Canvas>
This will be faster than setting the style. Some other things to keep in mind:
By far the most efficient way to write an itemRenderer is to extend UIComponent using an ActionScript class. You'll have complete control of the code, and the renderer will be as efficient as possible.
Start with the example above, switching styles, and write a simple itemRenderer extending UIComponent.
package renderers
{
import mx.controls.listClasses.IListItemRenderer;
import mx.core.UIComponent;
public class PriceItemRenderer extends UIComponent implements IListItemRenderer
{
public function PriceItemRenderer()
{
super();
}
}
}
You'll notice that not only did I write the class to extend UIComponent, I also have it implementing the IListItemRenderer interface. It is necessary to do this because a List control will expect any renderer to implement this interface, and if you do not, you'll get a runtime error as the list attempts to cast the renderer to this interface.
If you read the documentation on IListItemRenderer, you'll see that is an amalgamation of many other interfaces, most of which UIComponent implements for you. But there is one interface extended by IListItemRenderer that UIComponent does not implement: IDataRenderer. This requires you to add the code to give the itemRenderer class the data property you've been using all along.
If you attempt to use this class without implementing IDataRenderer, you'll get these errors when you compile the code:
Edit this class and change it to the following:
package renderers
{
import mx.controls.listClasses.IListItemRenderer;
import mx.core.UIComponent;
import mx.events.FlexEvent;
public class PriceItemRenderer extends UIComponent implements IListItemRenderer
{
public function PriceItemRenderer()
{
super();
}
// Internal variable for the property value.
private var _data:Object;
// Make the data property bindable.
[Bindable("dataChange")]
// Define the getter method.
public function get data():Object {
return _data;
}
// Define the setter method, and dispatch an event when the property
// changes to support data binding.
public function set data(value:Object):void {
_data = value;
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
}
}
I took the code directly from the Flex documentation for IDataRenderer, so you don't even have to type it yourself.
With that out of the way, you can add in the two labels.
private var posLabel:Label; private var negLabel:Label; set data function to call invalidateProperties(). This is important, because the change of the data has to change the text in the labels AND their visibility. public function set data(value:Object):void {
_data = value;
invalidateProperties();
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
Calling invalidateProperties() tells the Flex framework to call the commitProperties() function at the apppriate time.
createChildren() and create the labels, adding them to the display list of the component. Notice that in addition to creating the labels, their styles and visible properties are also set. override protected function createChildren() : void
{
super.createChildren();
posLabel = new Label();
posLabel.visible = false;
posLabel.setStyle("color", 0×00FF00);
addChild(posLabel);
negLabel = new Label();
negLabel.visible = false;
negLabel.setStyle("color", 0xFF0000);
addChild(negLabel);
}
commitProperties() to set the labels' text and visibility. In the past you've been overriding set data to make this type of change, and you can do that in this class, too, if you prefer. override protected
function commitProperties():void
{
super.commitProperties();
posLabel.text = data.price;
negLabel.text = data.price;
posLabel.visible = Number(data.price) > 0;
negLabel.visible = Number(data.price) < 0;
}
updateDisplayList() to size and position the labels. You must size the labels, because their default size is 0×0. This is another thing a Container class will do for you. Since this is a pretty simple itemRenderer, you can just set the labels' size to match the size of the itemRenderer. override protected function updateDisplayList(
unscaledWidth:Number, unscaledHeight:Number ) : void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
posLabel.move(0,0);
posLabel.setActualSize(unscaledWidth,unscaledHeight);
negLabel.move(0,0);
negLabel.setActualSize(unscaledWidth, unscaledHeight);
}
All this probably seems a bit complicated just to do this, but keep in mind that using a container will add a lot more code than this.
The UIComponent class is the basis for all visual Flex components—controls and containers. Here are some tips about using UIComponent as your itemRenderer.
updateDisplayList(). variableRowHeight in your list, you should also override the measure() function to give the list an idea of how big the itemRenderer is. This concludes my series on Flex itemRenderers. I hope these articles have given you a sense what you can accomplish in your Flex applications using itemRenderers, as well as best practices for how to manipulate their data, appearance and behavior. You can find more information about Flex itemRenderers in the Adobe Flex 3 documentation.

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License