Custom Spark item renderers

The Spark list-based controls, such as List and ComboBox, support custom item renderers. You can also use Spark item renderers with some MX controls, such as the MX DataGrid and MX Tree controls.

Define a custom Spark item renderer

Several Spark components represent lists of items. These list-based components, such as DataGroup, List, and DataGrid, let the application user scroll through the item list. Some components, such as List, also let you select one or more items from the list.

You define a custom item renderer to control the display of a data item in a list-based component. The appearance can include the font, background color, border, and any other visual aspects of the data item.

An item renderer also defines the appearance of a data item when the user interacts with it. For example, the item renderer can display the data item one way when the user hovers over the data item, and in a different way when the user selects the data item.

Many Spark components support both skins and item renderers. While the item renderer defines the appearance of the data item, the skin defines the complete visual appearance of the component. The skin can include borders, scroll bars, and any other aspects of the appearance of the component. For more information on skins, see Spark Skinning.

Item renderer architecture

Create an item renderer in MXML or ActionScript. The advantage to creating item renderers in MXML is that it requires the least amount of code because much of the item renderer functionality is built into the base class, ItemRenderer, that you use to define MXML item renderers.

ActionScript item renderers provide the best performance because they give you complete control over the implementation. In an ActionScript item renderer, you only implement the code necessary to support your application requirements. Create an ActionScript item renderer as a subclass of the spark.components.LabelItemRenderer class for mobile applications, and the mx.core.UIComponent class for desktop applications.

The Spark item renderer architecture is defined by interfaces. Regardless of how you create your item renderer, MXML or ActionScript, the item renderer typically implements two interfaces:

Item renderer interface

Implemented by

Use

IDataRenderer

Item renderer

Defines the data property used to pass information to an item renderer.

At a minimum, an item renderer must implement IDataRenderer to display data.

IItemRenderer

Item renderer

Defines the APIs that a component must implement to create an item renderer that can communicate with a host component to support user interaction with the data item. User interactions include selection, dragging, and the caret indicator. For some components, such as the Spark List control, user interaction includes item selection.

The list-based components that uses the item renderer is called the host component, or item renderer owner. To function as a host component, the component must implement the IItemRendererOwner interface.

Host component interface

Implemented by

Use

IItemRendererOwner

Host component of an item renderer

Defines the methods used by the host component to pass data to the item renderer.

Custom item renderer example

To better understand how item renderers work, examine the implementation of a custom item renderer. Shown below is the code for a custom MXML item renderer for the SkinnableDataContainer container that changes the font of the data item when the user hovers over the data item:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleCustomItemRenderer.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:states> 
        <s:State name="normal"/> 
        <s:State name="hovered"/> 
    </s:states> 
    
    <s:Label id="labelDisplay" 
        verticalCenter="0" 
        left="3" right="3" top="6" bottom="4" 
        fontSize.hovered='14' fontStyle.hovered="italic"/> 
</s:ItemRenderer>

The base class of this item renderer is the ItemRenderer class. The ItemRenderer class implements the IDataRenderer and IItemRenderer interfaces. It is also a subclass of the Group class, so it is itself a container. In the body of the item renderer, define the layout, view states, and child controls of the item renderer used to represent the data item.

The default layout of the ItemRenderer class is BasicLayout. In this example, since there is no specification for the layout property, the item renderer uses BasicLayout.

The item renderer can define view states. All view states are optional. In this example, you handle the normal and hovered view states. The normal state defines the appearance of the data item when there is no user interaction. The hovered view state defines the appearance when the user hovers the pointer over the data item.

This example uses the hovered view state to change the font when the user mouses over the data item. In this example, the custom item renderer displays the text in 14 point, italic font on mouse over. For more information on using view states in an item renderer, see Defining item renderer view states for a Spark container.

The Label control is centered vertically in the display area of the item renderer, and is constrained to be three pixels in from the left border, three pixels in from the right border, six pixels in from the top border, and four pixels in from the bottom border. You can use these same settings in your custom item renderers to mimic the look of the default Flex item renderer, or change them as necessary for your application.

The id of the Label control in the item renderer is labelDisplay. This is a specially named component in an item renderer. Flex writes the String representation of the data item to the component named labelDisplay. Flex also uses the labelDisplay component to determine the value of the baselinePosition property in the host component.

The following application uses this custom item renderer:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerSimpleIR.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:SkinnableDataContainer 
        itemRenderer="myComponents.MySimpleCustomItemRenderer"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:String>Bill Smith</fx:String> 
            <fx:String>Dave Jones</fx:String> 
            <fx:String>Mary Davis</fx:String> 
            <fx:String>Debbie Cooper</fx:String> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
</s:Application>

Differences between mobile and desktop item renderers

An item renderer is often designed to appear differently in a mobile application than in a desktop application. Therefore, while it is possible, you typically do not use the same item renderer in a mobile application and in a desktop application.

For example, the differences between an item renderer for a mobile and a desktop application include the following:
  • The size of a mobile item renderer tends to be larger than for a desktop item renderer.

  • An item renderer for the selected item on in a mobile application usually indicates selection with a checkmark or other icon. For a desktop application, item renderers usually show selection by changing the backgroundColor style.

  • The caret in a mobile application is usually indicated by changing the backgroundColor style. For a desktop application, the caret is usually indicated by drawing a border around the item.

The way you create item renderers can also depend on whether the application is for a desktop application or for a mobile application. You define item renderers in two ways:

  • MXML

    Use MXML to define item renderers for desktop applications. MXML item renderers are simple to implement, but do not provide the highest performance often necessary for mobile applications. You typically create an MXML item renderer as a subclass of the spark.components.ItemRenderer class.

    For a mobile application, if your component hosting the item renderer displays only has a few data items or does not support scrolling, you might be able to use an MXML item renderer.

  • ActionScript

    Use ActionScript for item renderers for applications that require the highest performance. For item renderers used in mobile applications, or for item renderers to use in both mobile and desktop applications, create them in ActionScript. For a mobile project, you typically create ActionScript item renderers as a subclass of the spark.components.LabelItemRenderer class.

Interacting with a mobile and desktop item renderer

The mx.core.UIComponent class defines the interactionMode style property that you use to configure components for the type of input used in the application. For the Halo and Spark themes, the default value is mouse to indicate that the mouse is the primary input device. For the Mobile theme, the default value is touch to indicate the primary input is the touch screen.

One important difference between item renderers for desktop and for mobile applications is the way you interact with the application. For desktop applications, you use a mouse to interact with the application. You can use the mouse to:
  • Move the mouse pointer over a data item. This is referred to as hovering over the item.

  • Select the item by clicking on it. Many Spark components let the user select multiple data items by using the Shift and Control keys in combination with the mouse.

  • Display a caret item. The caret item is the data item that currently has focus. The caret item can be the currently selected data item, or it can be a different item.

  • Drag and drop data items when enabled by the Spark control.

When you interact with an application on a mobile device, you often use a touch screen or a five-way navigation control, not a mouse. With a mobile application, the data items in a list-based control do not enter the hovered state, and you typically do not have to support drag and drop. Therefore, when implementing an item renderer for mobile applications, you do not have to worry about supporting those situations.

MXML item renderers define view states. View states provide MXML item renderers with a simple mechanism for handling the different states of the data item. In ActionScript item renderers, you do not use view states. Instead, you handle user interaction in the body of your item renderer.

Differences between down and selected item renderers in a mobile application

For mobile applications, an item renderer must distinguish between an item being in the down state and the item being in the selected state. An item is down when the user presses down on the item. An item is selected when the user releases their finger after pressing down on the item.

Note: In a desktop application, one where interactionMode is mouse, selection occurs on the mouseDown event.

When a user presses down on an item, the item renderer does not immediately enter the down state. Instead, the item renderer waits for the duration of time specified by the touchDelay property. The default delay duration specified by the touchDelay property is 100 ms.

This delay ensures that the user did not intend to initiate a scroll operation. If the item renderer immediately went to the down state, and the user intended to scroll, the item renderer would flicker from the normal state to the down state, and then back to the normal state.

Working with item renderers

Passing data to a Spark item renderer

The host component of the item renderer is called the item renderer's owner. The host component passes information to the item renderer by using the properties defined by the IDataRenderer and IItemRenderer interfaces.

The following table describes the properties of the IDataRenderer and IItemRenderer interfaces:

Item renderer property

Type

Description

Interface

data

Object

The data item to render or edit as defined in the data provider of the host component.

IDataRenderer

dragging

Boolean

Contains true if the item renderer is being dragged.

Mobile applications do not support drag and drop. Therefore, for an item renderer used only in a mobile application, you can define this property with a setter/getter that always returns false. To use the item renderer in a desktop application that supports drag and drop, you must implement it.

IItemRenderer

itemIndex

int

The index of the item in the data provider of the host component of the item renderer.

IItemRenderer

label

String

A String representation of the data item to display in the item renderer.

IItemRenderer

selected

Boolean

Contains true if the item renderer can show itself as selected.

Many Spark components, such as the DataGroup and SkinnableDataContainers support item renderers, but do not support the selection of a data item. Other Spark components,. such as List, ComboBox, and DataGrid, support the selection of a data item.

IItemRenderer

showsCaret

Boolean

Contains true if the item renderer can show itself as focused.

IItemRenderer

Your item renderer might also implement the hovered property. The hovered property is not defined by an interface but is implemented by many Flex item renderers. The following table describes the hovered property:

Item renderer property

Type

Description

Interface

hovered

Boolean

Contains true when the user hovers over the list item. Typically, the item renderer listens for the rollOver and rollOut events to set hovered and to update the display of the item renderer accordingly.

Mobile applications do not support hovered. For an item renderer used in a mobile application, you are not required to implement the hovered property. To use the item renderer in a desktop application, you must implement it. The predefined mobile item renderers supplied with Flex implement the hovered property so that you can use the item renderer in a mobile and desktop application.

None

The UIComponent class, the base class for all Flex components including item renderers, defines the owner property. The owner property contains a reference to the component that hosts the item renderer. For example, the SkinnableDataContainer can be the owner of an item renderer. From within the item renderer, you can access the host component by using the owner property.

The host component of an item renderer must implement the IItemRendererOwner interface. That interface defines the following methods to write information to the item renderer:

Host component method

Description

Interface

itemToLabel()

Converts the data item to a String representation.

Host components can override this method to customize the String conversion.

IItemRendererOwner

updateRenderer()

Write the data item as a String to the label property. Updates the owner property with a reference to the host component. The last thing this method does is set the data property of the item renderer.

Host components can override this method to write additional information to the item renderer.

IItemRendererOwner

Before you create a custom item renderer, decide how to pass the data item to the item renderer. In some situations, you want the host component to perform any processing on the data item before it passes it to the item renderer. If so, override the itemToLabel() and updateRenderer() methods in the host component. The item renderer then accesses the data by using the label property.

Instead of the host component processing the data item, the item renderer can perform the processing. If you want the item renderer to process the data item, use IDataRenderer.data property to pass it. The item renderer then accesses the data property and performs any processing on the data item before displaying it.

For an example that overrides the itemToLabel() and updateRenderer() methods, see Passing data using the IItemRenderer.label property. For an example that overrides the data property, see Passing data using the IIDataRenderer.data property.

Passing data using the IItemRenderer.label property

If the data item is a String, or a value that can easily be converted to a String, you can use the IItemRenderer.label property to pass it to the item renderer. If the data item is in a format that must be converted to a String representation, override the IItemRendererOwner.itemToLabel() method in the host component to customize the conversion.

Note: The example item renderers in this section are written in MXML. For examples written in ActionScript, see Create a Spark item renderer in ActionScript.

In the following example, the children of the SkinnableDataContainer container are Strings specifying different colors:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataContainerColor.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:MyComps="myComponents.*"> 
 
    <s:SkinnableDataContainer 
        itemRenderer="myComponents.MySimpleColorRenderer"> 
        <mx:ArrayList> 
            <fx:String>red</fx:String> 
            <fx:String>green</fx:String> 
            <fx:String>blue</fx:String> 
        </mx:ArrayList>  
    </s:SkinnableDataContainer> 
</s:Application>
This example uses a custom item renderer named MySimpleColorRenderer, defined in the file MySimpleColorRenderer.mxml, that shows the String text in a background of the matching color. Shown below is the MXML item renderer:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleColorRenderer.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    autoDrawBackground="false"> 
    
    <fx:Script> 
        <![CDATA[    
            
            // Property to hold the RGB color value. 
            [Bindable] 
            public var myColor:uint; 
        
            // Write String to labelDisplay component. 
            override public function set label(value:String):void 
            { 
                super.label = value; 
                labelDisplay.text = label; 
                
                // Determine the RGB color value from the data item. 
                if (label == "red") 
                    myColor = 0xFF0000; 
                if (label == "green") 
                    myColor = 0x00FF00; 
                if (label == "blue") 
                    myColor = 0x0000FF; 
            } 
        ]]> 
    </fx:Script> 
    
    <!-- Set the background color to the RGB color value.--> 
    <s:Rect width="100%" height="100%" alpha="0.5"> 
        <s:fill> 
            <s:SolidColor color="{myColor}" /> 
        </s:fill> 
    </s:Rect> 
 
    <!-- Display the color name --> 
    <s:Label id="labelDisplay"/> 
</s:ItemRenderer>

In this example, the item renderer overrides the label property to write the color to the Label control, and set the fill color of the Rect component.

This item renderer displays the data with no visual changes based on state. Therefore, it sets the ItemRenderer.autoDrawBackground property to false. This item renderer is useful for displaying data in the container when it does not have any user interaction. For an example of an item renderer that changes its display based on user interaction, see Controlling the background color using the autoDrawBackground property.

If you want to modify the String passed to the label property, you can override the itemToLabel() method in the host component. The itemToLabel() method has the following signature:
itemToLabel(item:Object):String

The method takes a single argument representing the data item. It returns a String representation of the data item for display in the item renderer.

In the following example, each data item is represented by an Object containing three fields. The custom SkinnableDataContainer container, called MyDataGroup, overrides the itemToLabel() method to format the Object as a String before passing the String to the item renderer. The example then uses the DefaultItemRenderer to display the text:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerOverride.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:MyComps="myComponents.*"> 
 
    <!-- Define a custom DataGroup container to override the itemToLabel() method. --> 
    <MyComps:MyDataGroup itemRenderer="spark.skins.spark.DefaultItemRenderer"> 
        <MyComps:layout> 
            <s:VerticalLayout/> 
        </MyComps:layout> 
 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/> 
        </mx:ArrayList> 
    </MyComps:MyDataGroup> 
</s:Application>

The MyDataGroup.mxml file defines the custom SkinnableDataContainer container that overrides the itemToLabel() method:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MyDataGroup.mxml --> 
<s:SkinnableDataContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"> 
    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout> 
 
    <fx:Script> 
        <![CDATA[        
            // Override to return the Object as a formatted String. 
            override public function itemToLabel(item:Object):String { 
                var tempString:String; 
                if (item == null) 
                    return " "; 
 
                tempString = item.firstName + " " + item.lastName 
                    + " " + ", ID: " + item.companyID; 
                return tempString; 
            } 
        ]]> 
    </fx:Script> 
</s:SkinnableDataContainer>

Passing data using the IIDataRenderer.data property

Rather than processing the data in the host component, you can let the item renderer perform all the processing of the data item for display. In this situation, use the ItemRenderer.data property to pass the data item to the item renderer. This technique lets you define a set of item renderers that display the same data in different ways depending on your application requirements.

Note: The example item renderers in this section are written in MXML. For examples written in ActionScript, see Create a Spark item renderer in ActionScript.
In the next example, each data item is represented by an Object that defines three fields:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerSimple.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:SkinnableDataContainer 
        itemRenderer="myComponents.MySimpleItemRenderer"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
</s:Application>

The SkinnableDataContainer uses a custom item renderer named MySimpleItemRenderer.mxml. The custom item renderer displays the firstName and lastName fields in a single Label control, and display the companyID in a second Label control:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleItemRenderer.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:HGroup verticalCenter="0" left="2" right="2" top="2" bottom="2"> 
        <s:Label text="{data.lastName}, {data.firstName}"/> 
        <s:Label text="{data.companyID}"/> 
    </s:HGroup> 
</s:ItemRenderer>

The data property contains an Object passed from the DataGroup container. The Object represents the data item in its original form. The renderer uses data binding to populate the controls in the item renderer from the data property. The two Label controls are defined in a Group container so that they can be layed out horizontally.

Rather than using data binding, you can override the data property in the item renderer. Within the override, you can modify the data or perform other processing, then set properties in the renderer. The following example shows an alternative implementation of MySimpleItemRenderer.mxml that overrides the data property:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleItemRendererDataOverride.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <fx:Script> 
        <![CDATA[ 
            
            override public function set data(value:Object):void { 
                super.data = value; 
                
                // Check to see if the data property is null. 
                if (value== null) 
                    return; 
                // If the data property is not null, 
                // set the Label controls appropriately. 
                nameLabel.text = value.firstName + ', ' + value.lastName; 
                compLabel.text = value.companyID; 
            } 
        ]]> 
    </fx:Script> 
    <s:HGroup verticalCenter="0" left="2" right="2" top="2" bottom="2"> 
        <s:Label id="nameLabel"/> 
        <s:Label id="compLabel"/> 
    </s:HGroup> 
</s:ItemRenderer>

Controlling the background display of an item renderer

An item renderer controls the background display of the data item in the host component. Typically, an item renderer changes the background display of the data item to reflect user interaction. For example, an item renderer can use a transparent background when there is no user interaction with the data item. It could draw a blue background when the data item is selected, and a different background when the user hovers over the data item.

Flex defines the following CSS styles to define background colors for the three common user interactions:

Interaction

Style

Value for Spark theme

Value for Mobile theme

none

contentBackgroundColor

0xFFFFFF (white)

0x464646 (dark grey)

hovered

rollOverColor

0xCEDBEF (light blue)

0xCEDBEF (light blue/grey)

selected

selectionColor

0xA8C6EE (dark blue)

0xB2B2B2 (light grey)

These colors are defined in the default.css file for the spark.swc and mobilecomponents.swc file. If you want your item renderer to mimic the color setting of Flex, use these same colors for setting the background color of your custom item renderers.

You can use these same styles in a custom item renderer to mimic the default background colors used by Flex component. Or, you can define your item renderers to use different colors and backgrounds.

If you define an MXML item renderer, you typically create it as a subclass of the ItemRenderer class. The ItemRenderer class defines the default background color for all types of user interactions. By default the item renderer draws a transparent background around the item when there is not user interaction. It draws a light-blue background around an item when you hover over it. For more information, see Controlling the background color using the autoDrawBackground property.

If you define an item renderer in ActionScript, you define the background colors of the data item. You can choose to implement your item renderer to use the predefined CSS styles, or define your own.

In your main application, you can redefine the CSS styles for the background colors. The following applications sets the rollOverColor style of the application to green:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerSimpleIRStyled.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <fx:Style> 
        @namespace s "library://ns.adobe.com/flex/spark"; 
        s|ItemRenderer { rollOverColor : green }       
    </fx:Style> 
    
    <s:SkinnableDataContainer 
        itemRenderer="myComponents.MySimpleCustomItemRenderer"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:String>Bill Smith</fx:String> 
            <fx:String>Dave Jones</fx:String> 
            <fx:String>Mary Davis</fx:String> 
            <fx:String>Debbie Cooper</fx:String> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
</s:Application>

Using an item renderer function with a Spark container

In some applications, you display different types of data items in a single container. In this scenario, each type of data item needs its own item renderer. Or, you mix data items and Flex components in a container. To mix data items and Flex components, define different item renderers for the data items and the Flex components.

You can use an item renderer function to examine each data item to determine which item renderer to use. The DataGroup.itemRendererFunction and SkinnableDataContainer.itemRendererFunction property takes a function with the following signature:

function itemRendererFunction(item:Object):ClassFactory

Where item is the data item, and the return value is the item renderer. If the child is a Flex component, return DefaultComplexItemRenderer to display the child in a Group container. Alternatively, return null to display the child with no renderer.

The following example defines an item renderer function to return one item renderer for data items defined as Object, and another item renderer for data items defined as String:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerFunction.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <fx:Script> 
        <![CDATA[ 
            
            import myComponents.MySimpleItemRendererFunction; 
            import spark.skins.spark.DefaultItemRenderer; 
        
            private function selectRenderer(item:Object):ClassFactory { 
                var classFactory:ClassFactory; 
                if (item is String) { 
                    // If the item is a String, use DefaultItemRenderer. 
                    classFactory = new ClassFactory(DefaultItemRenderer); 
                } 
                else { 
                    // If the item is an Object, use MySimpleItemRendererFunction. 
                    classFactory = new ClassFactory(MySimpleItemRendererFunction); 
                } 
                return classFactory; 
            } 
        ]]>  
    </fx:Script> 
 
    <s:DataGroup itemRendererFunction="selectRenderer"> 
        <s:layout> 
            <s:TileLayout requestedColumnCount="3"/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:String>617-555-1212</fx:String> 
            <fx:String>Newton</fx:String> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:String>617-555-5555</fx:String> 
            <fx:String>Newton</fx:String> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:String>617-555-6666</fx:String> 
            <fx:String>Newton</fx:String> 
        </mx:ArrayList>            
    </s:DataGroup> 
</s:Application>

You also use item renderer function when mixing data items and Flex components in the container. Flex components implement the IVisualElement interface, and therefore do not need an item renderer to draw them on the screen. In your item renderer function, you can determine if the data item corresponds to a Flex component. If so, the item renderer function returns the DefaultComplexItemRenderer, as the following example shows:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerFunctionVisual.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <fx:Script> 
        <![CDATA[ 
            import mx.core.IVisualElement; 
            
            import myComponents.MySimpleItemRendererEmployee; 
            import spark.skins.spark.DefaultComplexItemRenderer; 
        
            private function selectRenderer(item:Object):ClassFactory { 
                var classFactory:ClassFactory; 
                if(item is IVisualElement){ 
                    // If the item is a Flex component, use DefaultComplexItemRenderer. 
                    classFactory = new ClassFactory(DefaultComplexItemRenderer); 
                } 
                else if (item is Object){ 
                    // If the item is an Object, use MySimpleItemRendererFunction. 
                    classFactory = new ClassFactory(MySimpleItemRendererEmployee); 
                } 
                return classFactory; 
            } 
        ]]> 
    </fx:Script> 
 
    <s:DataGroup itemRendererFunction="selectRenderer"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/> 
            <s:Button label="Add Employee"/> 
        </mx:ArrayList> 
    </s:DataGroup> 
</s:Application>

Spark item renderer precedence

The DataGroup and SkinnableDataContainer containers use the follow rules to determine the item renderer for a child:

  1. If the itemRendererFunction property is defined, call the associated function to obtain the item renderer. If the function returns null, go to rule 2.

  2. If the itemRenderer property is defined, use the specified item renderer to display the item.

  3. If the item is implements mx.core.IVisualElement and is of type flash.display.DisplayObject, use it directly.

  4. Dispatch a runtime error if no item renderer found.

Creating a recyclable item renderer for virtual layout

With virtual layout disabled, the DataGroup and SkinnableDataContainer containers create one instance of the item renderer for each child. With virtual layout enabled, the container only creates enough item renderers to display its currently visible children. Virtual layout greatly reduces the overhead required to use the DataGroup and SkinnableDataContainer containers.

With virtual layout enabled, when a child is moved off the visible area of the container, its item renderer is recycled. When the item renderer is reused, its data property is set to the data item representing the new child. Therefore, if a recycled item renderer performs any actions based on the value of the data property, it must first check that the property is not null.

When the item renderer is reassigned, Flex also calls the updateRenderer() method of the item renderer owner. This method must set the owner and label properties on the item renderer. Subclasses of SkinnableDataContainer, can use the updateRenderer() method to set additional properties on the item renderer.

Because a container can reuse an item renderer, ensure that you fully define its state. For example, you use a CheckBox control in an item renderer to display a true (checked) or false (unchecked) value based on the current value of the data property. A common mistake is to assume that the CheckBox control is always in its default state of unchecked and only inspect the data property for a value of true.

However, remember that the CheckBox can be recycled and had previously been checked. Therefore, inspect the data property for a value of false, and explicitly uncheck the control if it is checked, as the following example shows:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleItemRendererCB.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    dataChange="setMgr();"> 
    
    <fx:Script> 
        <![CDATA[ 
            private function setMgr():void { 
                // Check to see if the data property is null. 
                if (data == null) 
                    return; 
                // If the data property is not null, 
                // set the CheckBox control appropriately.. 
                if (data.manager == "yes") { 
                    mgr.selected = true; 
                } 
                else { 
                    mgr.selected = false;                    
                } 
            } 
        ]]> 
    </fx:Script> 
 
    <s:HGroup verticalCenter="0" left="2" right="2" top="2" bottom="2"> 
        <s:Label text="{data.lastName}, {data.firstName}"/>               
        <s:Label text="{data.companyID}"/>     
        <s:CheckBox id="mgr"/>                  
    </s:HGroup> 
</s:ItemRenderer>

Use the dataChange event of the ItemRenderer class to detect the change to its data property. This event is dispatched whenever the data property changes. Alternatively, you can override the data property.

Alternatively, you can override the ItemRenderer.data property itself, as the following example shows:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleItemRendererCBData.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
    
    <fx:Script> 
        <![CDATA[ 
        
            override public function set data(value:Object):void { 
                super.data = value; 
 
                // Check to see if the data property is null. 
                if (value== null) 
                    return; 
                // If the data property is not null, 
                // set the CheckBox control appropriately.. 
                if (value.manager == "yes") { 
                    mgr.selected = true; 
                } 
                else { 
                    mgr.selected = false; 
                } 
            } 
        ]]> 
    </fx:Script> 
 
    <s:HGroup verticalCenter="0" left="2" right="2" top="2" bottom="2"> 
        <s:Label text="{data.lastName}, {data.firstName}"/>               
        <s:Label text="{data.companyID}"/>     
        <s:CheckBox id="mgr"/> 
    </s:HGroup> 
</s:ItemRenderer>

Defining a typical item for determining the size of an item renderer

When using virtual layout with the DataGroup and SkinnableDataContainer containers, you can pass to the container a data item that defines a typical data item. The container then uses the typical data item, and the associated item renderer, to determine the default size of the child. By defining the typical item, the container does not have to size each child as it is drawn on the screen.

If you do not specify the data item, by default the control uses the first item in the data provider as the typical data item.

Use the typicalItem property of the container to specify the data item, as the following example shows:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerTypicalItem.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
    
    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout> 
 
    <fx:Script> 
        <![CDATA[ 
            [Bindable] 
            public var typicalObj:Object = { 
                    firstName:"Long first name", 
                    lastName:"Even longer last name", 
                    companyID:"123456", 
                    manager:"yes" 
            }; 
        ]]> 
    </fx:Script> 
 
    <s:Scroller> 
        <s:DataGroup itemRenderer="myComponents.MySimpleItemRendererCB" 
            height="100" 
            typicalItem="{typicalObj}" > 
            <s:layout> 
                <s:VerticalLayout useVirtualLayout="true"/> 
            </s:layout> 
            <mx:ArrayList> 
                <fx:Object firstName="Bill" lastName="Smith" 
                    companyID="11233" manager="yes"/> 
                <fx:Object firstName="Dave" lastName="Jones" 
                    companyID="13455" manager="no"/> 
                <fx:Object firstName="Mary" lastName="Davis" 
                    companyID="11543" manager="yes"/> 
                <fx:Object firstName="Debbie" lastName="Cooper" 
                    companyID="14266" manager="no"/> 
                <fx:Object firstName="Bob" lastName="Martins" 
                    companyID="11233" manager="yes"/> 
                <fx:Object firstName="Jack" lastName="Jones" 
                    companyID="13455" manager="no"/> 
                <fx:Object firstName="Sam" lastName="Johnson" 
                    companyID="11543" manager="yes"/> 
                <fx:Object firstName="Tom" lastName="Fitz" 
                    companyID="14266" manager="no"/> 
                <fx:Object firstName="Dave" lastName="Mead" 
                    companyID="11233" manager="yes"/> 
                <fx:Object firstName="Dave" lastName="Jones" 
                    companyID="13455" manager="no"/> 
                <fx:Object firstName="Mary" lastName="Davis" 
                    companyID="11543" manager="yes"/> 
                <fx:Object firstName="Debbie" lastName="Cooper" 
                    companyID="14266" manager="no"/> 
            </mx:ArrayList>            
        </s:DataGroup> 
    </s:Scroller> 
</s:Application>

In this example, you define typicalObj, an Object that represents a data item with a long value for the firstName and lastName fields. You then pass typicalObj to the typicalItem property of the container. The container uses that data item, and the associated item renderer, to determine the size of the children.

Specifying a value for the typicalItem property passes that value, and the associated item renderer, to the typicalLayoutElement property of the layout of the container. For more information on the typicalLayoutElement property, see Set the row height or column width of a layout.

Create a Spark item renderer in MXML

MXML item renderers require the least amount of code to create. Typically, you create an MXML item renderer as a subclass of the ItemRenderer class.

Controlling the background color using the autoDrawBackground property

To completely control the background color of an item renderer, set the ItemRenderer.autoDrawBackground property to false. When you set that property to false, your item renderer is responsible for displaying the background colors for all user interactions.

The following custom item renderer alternates the background color between white and green for the items in a SkinnableDataContainer:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MyAlternatingItemRenderer.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    autoDrawBackground="false"> 
    
    <fx:Script> 
        <![CDATA[ 
            
            // Make the default background color white. 
            [Bindable] 
            public var myBGColor:int = 0xFFFFFF; 
            
            // Override the itemIndex set function to draw a 
            // white background behind even number items, 
            // and a green background behind odd numbered items. 
            override public function set itemIndex(value:int):void { 
                if ((value%2) == 0) { 
                    myBGColor= 0xFFFFFF; 
                } 
                if ((value%2) == 1) { 
                    myBGColor= 0xCCFF66; 
                } 
            } 
        ]]> 
    </fx:Script> 
 
    <s:states> 
        <s:State name="normal"/> 
        <s:State name="hovered"/> 
    </s:states> 
    <s:Rect id="myRect" 
        left="0" right="0" top="0" bottom="0" 
        alpha="1.0"> 
        <s:stroke> 
            <s:SolidColorStroke 
                color="0xA8C6EE" 
                weight="1"/> 
        </s:stroke> 
        <s:fill> 
            <!-- Bind the myBGColor property to the fill color. --> 
            <s:SolidColor 
                color="{myBGColor}"/> 
        </s:fill> 
    </s:Rect>     
    
    <s:Label id="labelDisplay" 
        verticalCenter="0" 
        left="3" right="3" top="6" bottom="4" 
        fontSize.hovered='14' fontStyle.hovered="italic"/> 
</s:ItemRenderer>

This example overrides the itemIndex property of the ItemRenderer class. The itemIndex property contains the index of the data item in the data provider of the host component. In the override, set the background color to green for odd-numbered items, and to white for even-numbered items.

The following application uses this item renderer:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerAlternatingIR.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:SkinnableDataContainer 
        itemRenderer="myComponents.MyAlternatingItemRenderer"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:String>Bill Smith</fx:String> 
            <fx:String>Dave Jones</fx:String> 
            <fx:String>Mary Davis</fx:String> 
            <fx:String>Debbie Cooper</fx:String> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
</s:Application>

Defining item renderer view states for a Spark container

Item renderers support optional view states. You typically use view states in MXML item renderers to control the appearance of a data item based on user interaction with the item. The ItemRenderer class supports all views states so that you can use those item renderers with list-based classes.

Flex defines the following view states that you can support in your item renderers.
  • normal The data item has no user interaction.

  • hovered The mouse is over the data item.

  • selected The data item is selected.

  • dragging The data item is being dragged.

  • normalAndShowCaret The data item is in the normal state, and it has focus in the item list.

  • hoveredAndShowCaret The data item is in the hovered state, and it has focus in the item list.

  • selectedAndShowCaret The data item is in the normal state, and it has focus in the item list.

When the user interacts with a control in a way that changes the view state of the item renderer, Flex first determines if the renderer defines that view state. If the item renderer supports the view state, Flex sets the item renderer to use that view state. If the item renderer does not supports the view state, Flex does nothing.

The selected, normalAndShowCaret, hoveredAndShowCaret, and selectedAndShowCaret view states are supported by the list-based components. The list-based components are subclasses of the spark.components.supportClasses.ListBase class. The DataGroup and SkinnableDataContainer containers do not implement these view states.

The view states supported by your item renderers, and the action performed by a change to each view state, are determined by your application requirements. For example, you can alter the display of the data renderer based on the view state, show different data, or do nothing. Your item renderer can also define additional view states.

In the next example, you define a SkinnableDataContainer to display an Object with four fields: firstName, lastName, companyID, and phone:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerSimpleStates.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:SkinnableDataContainer itemRenderer="myComponents.MySimpleItemRendererWithStates"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" 
                companyID="11233" phone="617-555-1212"/> 
            <fx:Object firstName="Dave" lastName="Jones" 
                companyID="13455" phone="617-555-1213"/> 
            <fx:Object firstName="Mary" lastName="Davis" 
                companyID="11543" phone="617-555-1214"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" 
                companyID="14266" phone="617-555-1215"/> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
</s:Application>
The following item renderer displays the text of the Label controls in bold, blue font for the hover state:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleItemRendererWithStates.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    autoDrawBackground="false"> 
 
    <s:states> 
        <s:State name="normal"/> 
        <s:State name="hovered"/> 
    </s:states> 
    
    <s:HGroup verticalCenter="0" horizontalCenter="0"> 
        <s:Label text="{data.lastName}, {data.firstName}" 
            color.hovered="blue" 
            fontWeight.hovered="bold"/> 
        <s:Label text="{data.companyID}" 
            color.hovered="blue" 
            fontWeight.hovered="bold"/> 
        <s:Label text="{data.phone}" 
            color.hovered="blue" 
            fontWeight.hovered="bold"/> 
    </s:HGroup> 
</s:ItemRenderer>

Because a SkinnableDataContainer does not support the selected view state, the item renderer does not define any settings for the selected state.

You can also include a transition in an item renderer. A transition plays whenever you change a view state. The following item renderer uses a transition to display the company ID and telephone number of the employee on mouse over:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\myComponents\MySimpleItemRendererWithTrans.mxml --> 
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    autoDrawBackground="false"> 
 
    <s:states> 
        <s:State name="normal"/> 
        <s:State name="hovered"/> 
    </s:states> 
 
    <s:transitions> 
        <s:Transition fromState="normal"> 
            <s:Sequence> 
                <s:Resize target="{this}" /> 
                <mx:SetPropertyAction targets="{[cID, empPhone]}" 
                    name="visible" value="true" /> 
             </s:Sequence> 
        </s:Transition> 
        <s:Transition toState="normal"> 
            <s:Sequence> 
                <mx:SetPropertyAction targets="{[cID, empPhone]}" 
                    name="visible" value="false" /> 
                <s:Resize target="{this}" /> 
            </s:Sequence> 
        </s:Transition> 
    </s:transitions> 
 
    <s:VGroup verticalCenter="0" horizontalCenter="0"> 
        <s:Label text="{data.lastName}, {data.firstName}" 
            color.hovered="blue" 
            fontWeight.hovered="bold"/>               
        <s:Label id="cID" 
            includeIn="hovered" 
            includeInLayout.hovered="true" 
            includeInLayout.normal="false" 
            text="{data.companyID}"/> 
        <s:Label id="empPhone" 
            includeIn="hovered" 
            includeInLayout.hovered="true" 
            includeInLayout.normal="false" 
            text="{data.phone}"/> 
    </s:VGroup> 
</s:ItemRenderer>
The following application uses this item renderer:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerSimpleStatesTransition.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:SkinnableDataContainer itemRenderer="myComponents.MySimpleItemRendererWithTrans"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" 
                companyID="11233" phone="617-555-1212"/> 
            <fx:Object firstName="Dave" lastName="Jones" 
                companyID="13455" phone="617-555-1213"/> 
            <fx:Object firstName="Mary" lastName="Davis" 
                companyID="11543" phone="617-555-1214"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" 
                companyID="14266" phone="617-555-1215"/> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
</s:Application>

For more information on view states, see View states. For more information on transitions, see Transitions.

Defining an inline item renderer for a Spark container

The examples of item renderers shown above are all defined in an MXML file. That makes the item renderer highly reusable because you can reference it from multiple containers.

You can also define inline item renderers in the MXML definition of a component. By using an inline item renderer, your code can all be defined in a single file. However, it is not easy to reuse an inline item renderer.

The following example uses an inline item renderer with the SkinnableDataContainer container:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerInline.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <s:SkinnableDataContainer> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/> 
        </mx:ArrayList> 
        <s:itemRenderer> 
            <fx:Component> 
                <s:ItemRenderer> 
                    <s:Group verticalCenter="0" left="2" right="2" top="2" bottom="2"> 
                        <s:layout> 
                            <s:HorizontalLayout/> 
                        </s:layout> 
                        <s:Label text="{data.lastName}, {data.firstName}"/> 
                        <s:Label text="{data.companyID}"/> 
                    </s:Group> 
                </s:ItemRenderer> 
            </fx:Component> 
        </s:itemRenderer>  
    </s:SkinnableDataContainer> 
</s:Application>

Notice that you define the item renderer inline by using the itemRenderer property of the DataGroup container. The first child tag of the itemRenderer property is always the <fx:Component> tag. Inside the <fx:Component> tag is the same code as was in the MySimpleItemRenderer.mxml file shown above.

Items allowed in an inline component

There is only one restriction on what you can and cannot do in an inline item renderer. You cannot create an empty <fx:Component></fx:Component> tag. For example, you can combine effect and style definitions in an inline item renderer along with your rendering logic.

You can include the following items in an inline item renderer:

  • Binding tags

  • Effect tags

  • Metadata tags

  • Model tags

  • Scripts tags

  • Service tags

  • State tags

  • Style tags

  • XML tags

  • id attributes, except for the top-most component

Using the Component tag

The <fx:Component> tag defines a new scope in an MXML file, where the local scope of the item renderer is defined by the MXML code block delimited by the <fx:Component> and </fx:Component> tags. To access elements outside the local scope of the item renderer, you prefix the element name with the outerDocument keyword.

For example, you define one variable named localVar in the scope of the main application. You define another variable with the same name in the scope of the item renderer. From within the item renderer, you access the application's localVar by prefixing it with outerDocument keyword, as the following example shows:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerInlineScope.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <fx:Script> 
        <![CDATA[ 
            // Variable in the Application scope. 
            [Bindable]                        
            public var localVar:String="Application scope"; 
        ]]> 
    </fx:Script> 
 
    <s:SkinnableDataContainer> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/> 
        </mx:ArrayList>            
        <s:itemRenderer> 
            <fx:Component> 
                <s:ItemRenderer> 
                    <fx:Script> 
                        <![CDATA[ 
                            // Variable in the Renderer scope. 
                            [Bindable]                        
                            public var localVar:String="Renderer scope"; 
                        ]]> 
                    </fx:Script> 
                    <s:Group verticalCenter="0" left="2" right="2" top="2" bottom="2"> 
                        <s:layout> 
                            <s:HorizontalLayout/> 
                        </s:layout> 
                        <s:Label text="{data.lastName}, {data.firstName}"/>               
                        <s:Label text="{data.companyID}"/>             
                        <s:Label text="{'Renderer localVar = ' + localVar}"/> 
                        <s:Label text="{'Application localVar = ' + outerDocument.localVar}"/> 
                    </s:Group> 
                </s:ItemRenderer> 
            </fx:Component> 
        </s:itemRenderer>  
    </s:SkinnableDataContainer> 
</s:Application>
Creating a reusable inline item renderer

Rather than defining an inline item renderer in the definition of a component, you can define a reusable inline item renderer for use in multiple locations in your application.

To create a reusable inline item renderer, specify the className property of the <fx:Component> tag. By naming the class, you define a way to reference the item renderer, and the elements of the item renderer.

The following example uses the <fx:Component> tag to define an inline item renderer for two containers:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\spark\SparkDataGroupContainerInlineReuse.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout> 
 
    <fx:Declarations> 
        <fx:Component id="inlineRenderer" className="myIR"> 
            <s:ItemRenderer> 
                <s:Group verticalCenter="0" horizontalCenter="0"> 
                    <s:layout> 
                        <s:HorizontalLayout/> 
                    </s:layout> 
                    <s:Label text="{data.lastName}, {data.firstName}"/> 
                    <s:Label text="{data.companyID}"/> 
                </s:Group>             
            </s:ItemRenderer> 
        </fx:Component>        
    </fx:Declarations> 
 
    <s:SkinnableDataContainer itemRenderer="myIR"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
    <s:SkinnableDataContainer itemRenderer="myIR"> 
        <s:layout> 
            <s:VerticalLayout/> 
        </s:layout> 
        <mx:ArrayList> 
            <fx:Object firstName="Jim" lastName="Sullivan" companyID="11233"/> 
            <fx:Object firstName="Joan" lastName="Connors" companyID="13455"/> 
            <fx:Object firstName="Jack" lastName="Wilson" companyID="11543"/> 
            <fx:Object firstName="Jeff" lastName="Lodge" companyID="14266"/> 
        </mx:ArrayList> 
    </s:SkinnableDataContainer> 
</s:Application>

In this example, you use data binding to specify the renderer as the value of the itemRenderer property for the two containers.

Create a Spark item renderer in ActionScript

To ensure that your application achieves the highest performance, implement item renderers in ActionScript. Typically, you create item renderers in ActionScript only for mobile applications, but you can create them for desktop application as well.

The item renderer typically implements two interfaces:

Item renderer interface

Implemented by

Use

IDataRenderer

Item renderer

Defines the data property used to pass information to an item renderer.

At a minimum, an item renderer must implement IDataRenderer to display data.

IItemRenderer

Item renderer

Defines the APIs that a component must implement to create an item renderer that can communicate with a host component to support user interaction with the data item. User interactions include selection, dragging, and the caret indicator. For some components, such as the Spark List control, user interaction includes item selection.

Create an ActionScript item renderer in one of the following ways:

  • Create an ActionScript subclass from an existing item renderer class, such as spark.components.LabelItemRenderer, spark.components.IconItemRenderer, or spark.components.supportClasses.ItemRenderer. The existing item renderer classes already implement all necessary interfaces.

    For the highest performance in a mobile application, create a subclass of spark.components.LabelItemRenderer. In your subclass, you can control the background display and the layout of the data items.

    If you want to use the built-in Flex layout mechanism, and are not as concerned with performance, create a subclass of spark.components.supportClasses.ItemRenderer.

    For more information, see Create an ActionScript item renderer as a subclass of the LabelItemRenderer class.

    For more information on using LabelItemRenderer and IconItemRenderer, see Using a mobile item renderer with a Spark list-based control.

  • Create an ActionScript subclass of the mx.core.UIComponent class.

    By implementing an item renderer as a subclass of the UIComponent class, you can obtain the best performance because you only have to implement the logic necessary to support your application. However, basing an item renderer on UIComponent requires the most effort. To be used as an item renderer, your subclass must implement the mx.core.IDataRenderer and spark.components.IItemRenderer interfaces.

For example implementations of item renderers written in ActionScript, view the source code for the spark.components.LabelItemRenderer, spark.components.IconItemRenderer, and spark.components.supportClasses.ItemRenderer classes.

Creating item renderers in ActionScript

To define an item renderer in ActionScript, override the necessary methods from the parent class, and call any necessary invalidation methods from within your overrides. For general information on this process, see Create advanced Spark visual components in ActionScript.

The methods that you have to override in your class depend on the parent class of the item renderer. You optionally can override one or more of the following protected methods of the parent class:

Method

Description

commitProperties()

Commits any changes to component properties, either to make the changes occur at the same time or to ensure that properties are set in a specific order.

For more information, see Implementing the commitProperties() method.

createChildren()

Creates any child components of the component. For example, the ComboBox control contains a TextInput control and a Button control as child components.

For more information, see Implementing the createChildren() method.

measure()

Sets the default size and default minimum size of the component.

For more information, see Implementing the measure() method.

styleChanged()

Detects changes to style properties.

For more information, see Overriding the styleChanged() method.

updateDisplayList()

Sizes and positions the children of the component on the screen based on all previous property and style settings, and draws any skins or graphic elements used by the component. The parent container for the component determines the size of the component itself.

Note: You typically only have to implement this method when you use the mx.core.UIComponent class as the base class of your item renderer. You do not have to implement it when creating a subclass of the LabelItemRenderer class. Override LabelItemRenderer.drawBackground() and LabelItemRenderer.layoutContent() instead.

For more information, see Implementing the updateDisplayList() method.

If the parent class is the LabelItemRenderer, you typically override one or both of the following methods:

Method

Description

drawBackground()

Defines the background display of the item renderer.

layoutContents()

Lays out the children of the item renderer.

Flex uses an invalidation mechanism to synchronize modifications to components. Flex implements the invalidation mechanism as a set of methods that you call to signal that something about the component has changed and requires Flex to call the component's commitProperties(), measure(), or updateDisplayList() methods.

The following table describes the invalidation methods:

Invalidation method

Description

invalidateProperties()

Marks a component so that its commitProperties() method gets called during the next screen update.

invalidateSize()

Marks a component so that its measure() method gets called during the next screen update.

invalidateDisplayList()

Marks a component so that its updateDisplayList() methods get called during the next screen update.

When a component calls an invalidation method, it signals to Flex that the component must be updated. When multiple components call invalidation methods, Flex coordinates the updates so that they all occur together during the next screen update. For more information on these methods, see About the invalidation methods.

Create an ActionScript item renderer as a subclass of the LabelItemRenderer class

The following example shows a view component for a mobile application:
<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\mobile\views\ListColor.mxml --> 
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    title="Colors"> 
    <s:layout> 
        <s:VerticalLayout paddingTop="10"/> 
    </s:layout> 
    
    <s:Label text="Favorites"/> 
    <s:SkinnableDataContainer 
        itemRenderer="myComponents.MySimpleColorRenderer"> 
        <mx:ArrayList> 
            <fx:String>red</fx:String> 
            <fx:String>green</fx:String> 
            <fx:String>blue</fx:String> 
        </mx:ArrayList>  
    </s:SkinnableDataContainer> 
</s:View>

In this example, the SkinnableDataContainer contains three data items corresponding to three colors. In this example, you define an item renderer in the file MySimpleColorRenderer.as. Your custom item renderer displays the text of the data item and changes the background color of the data item to match the text.

Because this is a mobile application, for optimal performance create the item renderer as a subclass of the LabelItemRenderer class. This example does not change the way the data item is layed out in the container, only its background color. Therefore, you only override the LabelItemRenderer.drawBackground() method, and not the LabelItemRenderer.layoutContent() method.

The MySimpleColorRenderer.as item renderer is shown below:
package myComponents 
{ 
    // containers\mobile\myComponents\MySimpleColorRenderer .as 
    import spark.components.LabelItemRenderer; 
    
    public class MySimpleColorRenderer extends LabelItemRenderer 
    { 
        public function MySimpleColorRenderer() { 
            super(); 
        } 
        
        // Use the value of the myColor property to draw 
        // the background color of the item in the list. 
        override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void { 
            // Define a var to hold the color. 
            var myColor:uint; 
 
            // Determine the RGB color value from the label property. 
            if (data == "red") 
                myColor = 0xFF0000; 
            if (data == "green") 
                myColor = 0x00FF00; 
            if (data == "blue") 
                myColor = 0x0000FF; 
 
            graphics.beginFill(myColor, 1); 
            graphics.drawRect(0, 0, unscaledWidth, unscaledHeight); 
            
        } 
    } 
}

This item renderer accesses the LabelItemRenderer.data property in the override of the drawbackground() method to determine the background color of the item. The label property contains the String value to display in the item renderer.

Override the LabelItemRenderer.layoutComponents() method in an item renderer

By default, the LabelItemRenderer class uses a single spark.components.supportClasses.StyleableTextField control to display a String. The name of the StyleableTextField control in the item renderer is labelDisplay.

In the next example, you define an item renderer to display multiple fields of a data item in separate StyleableTextField controls in the item renderer. This example uses the predefined labelDisplay control to display the first and last name fields of the data item. It then adds a second StyleableTextField control to display the company ID field.

Shown below is the view component for the mobile application:

<?xml version="1.0" encoding="utf-8"?> 
<!-- containers\mobile\views\EmployeeMainViewIR.mxml --> 
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    title="Employees View Main"> 
    <s:layout> 
        <s:VerticalLayout paddingTop="10"/> 
    </s:layout> 
 
    <fx:Script> 
        <![CDATA[ 
            public function myLabelFunction(item:Object):String { 
                return item.lastName + ', ' + item.firstName;; 
            } 
        ]]> 
    </fx:Script> 
    
    <s:Label text="Select an employee name"/> 
    <s:List id="myList" 
        width="100%" height="100%" 
        itemRenderer="myComponents.MyGroupItemRenderer" 
        labelFunction="myLabelFunction"> 
        <s:ArrayCollection> 
            <fx:Object firstName="Bill" lastName="Smith" companyID="11233"/> 
            <fx:Object firstName="Dave" lastName="Jones" companyID="13455"/> 
            <fx:Object firstName="Mary" lastName="Davis" companyID="11543"/> 
            <fx:Object firstName="Debbie" lastName="Cooper" companyID="14266"/> 
        </s:ArrayCollection> 
    </s:List> 
</s:View>
The List control uses the itemRenderer property to specify the name of the custom item renderer as MyGroupItemRenderer.as. In MyGroupItemRenderer.as, you:
  • Define the StyleableTextField control named compLabelDisplay.

  • Override the protected createChildren() method to create the compLabelDisplay control.

  • Override the protected styleChanged() method to propagate and style changes to the compLabelDisplay control.

  • Override the data property to initialize the compLabelDisplay control. The data property contains the original Object representing the data item in the List control.

  • Override the measure() method to calculate the size of the labelDsiplay and compLabelDisplay controls.

  • Override the layoutContents() method to size and position the labelDisplay and compLabelDisplay controls. The override uses the padding styles to calculate the availale space for the components.

Shown below is the definition of MyGroupItemRenderer, the item renderer:
package myComponents 
{ 
    // containers\mobile\myComponents\MyGroupItemRenderer.as 
    import spark.components.LabelItemRenderer; 
    import spark.components.supportClasses.StyleableTextField; 
 
    public class MyGroupItemRenderer extends LabelItemRenderer 
    { 
        public function MyGroupItemRenderer(){ 
            super(); 
        } 
        
        // Define the StyleableTextField control used 
        // to display the company ID. 
        public var compLabelDisplay:StyleableTextField; 
        
        // The distance between the label and the company ID. 
        public var verticalGap:Number = 10; 
        
        // Override createChildren() to create the StyleableTextField control. 
        override protected function createChildren():void { 
            super.createChildren(); 
            
            // Make sure it does not already exist. 
            if (!compLabelDisplay) { 
                compLabelDisplay = new StyleableTextField(); 
                
                // Specify The object that provides styles for the control. 
                // This property must be set for the control to pick up 
                // the correct styles. 
                compLabelDisplay.styleName = this; 
                
                // Set basic attributes of the control. 
                compLabelDisplay.editable = false; 
                compLabelDisplay.selectable = false; 
                compLabelDisplay.multiline = false; 
                compLabelDisplay.wordWrap = false; 
                
                // Add the control as a child of the item renderer. 
                addChild(compLabelDisplay); 
            } 
        } 
        
        // Override styleChanged() to proopgate style changes to compLabelDisplay. 
        override public function styleChanged(styleName:String):void { 
            super.styleChanged(styleName); 
            
            // Pass any style changes to compLabelDisplay. 
            if (compLabelDisplay) 
                compLabelDisplay.styleChanged(styleName); 
        } 
        
        // Override the data property to initialize compLabelDisplay. 
        // The label function in the view specifies the String 
        // displayed in labelDisplay. 
        override public function set data(value:Object):void { 
            super.data = value; 
            
            compLabelDisplay.text = String(value.companyID); 
        } 
        
        // Override measure() to calculate the size required by the item renderer. 
        override protected function measure():void { 
            // Measure the labelDisplay by calling super.measure() 
            super.measure(); 
 
            // Then consider the compLabelDisplay if it exists. 
            if (compLabelDisplay) 
            { 
                var horizontalPadding:Number = getStyle("paddingLeft") + getStyle("paddingRight"); 
                var verticalPadding:Number = getStyle("paddingTop") + getStyle("paddingBottom"); 
                
                // Commit the styles changes to compLabelDisplay. 
                // This method must be called before the text is displayed, 
                // and any time the styles have changed. 
                // This method does nothing if the styles have already been committed. 
                compLabelDisplay.commitStyles(); 
                measuredWidth =  Math.max(getElementPreferredWidth(labelDisplay), getElementPreferredWidth(compLabelDisplay)) 
                measuredWidth += horizontalPadding; 
                
                measuredHeight =  getElementPreferredHeight(labelDisplay); 
                measuredHeight += getElementPreferredHeight(compLabelDisplay); 
                measuredHeight += verticalPadding + verticalGap; 
            } 
        } 
        
        // Override layoutContents() to lay out the item renderer. 
        override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void { 
            // Because you are handling the layout of both the 
            // predefined labelDisplay component and the new 
            // compLabelDisplay component, you do not have to call 
            // super.layoutContents(). 
            
            // Make sure labelDisplay and compLabelDisplay exist. 
            if (!labelDisplay) 
                return; 
            if (!compLabelDisplay) 
                return; 
            
            // Get the padding from the associated styles. 
            var paddingLeft:Number = getStyle("paddingLeft"); 
            var paddingRight:Number = getStyle("paddingRight"); 
            var paddingTop:Number = getStyle("paddingTop"); 
            var paddingBottom:Number = getStyle("paddingBottom"); 
            
            // Calculate the available space for the component. 
            var viewWidth:Number  = unscaledWidth - paddingLeft - paddingRight; 
            var viewHeight:Number = unscaledHeight - paddingTop - paddingBottom; 
            
            // Calcualte the size of the labelDisplay component. 
            var labelWidth:Number = Math.max(viewWidth, 0); 
            var labelHeight:Number = 0; 
            
            if (label != "") { 
                labelDisplay.commitStyles(); 
                
                // Reset text if it was truncated before. 
                if (labelDisplay.isTruncated) 
                    labelDisplay.text = label; 
                
                labelHeight = getElementPreferredHeight(labelDisplay); 
            } 
            
            // Set the size and position of the labelDisplay component. 
            setElementSize(labelDisplay, labelWidth, labelHeight);    
            setElementPosition(labelDisplay, paddingLeft, paddingTop); 
            
            // Attempt to truncate the text now that we have its official width 
            labelDisplay.truncateToFit(); 
            
            // Size and position the compLabelDisplay component. 
            var compLabelWidth:Number = Math.max(viewWidth, 0); 
            var compLabelHeight:Number = 0; 
            
            compLabelDisplay.commitStyles(); 
            compLabelHeight = getElementPreferredHeight(compLabelDisplay); 
            
            setElementSize(compLabelDisplay, compLabelWidth, compLabelHeight); 
            setElementPosition(compLabelDisplay, paddingLeft, paddingTop + labelHeight + verticalGap); 
        } 
    } 
}

Using a Spark item renderer with an MX control

Many MX list-based controls, such as the DataGrid, AdvancedDataGrid, and Tree, support item renderers. These three MX list-based controls also support item editors. Item editors let you create a custom view of data during the editing process. The item editor returns the new data back to the control so that the control can update its data provider.

Note: Many MX controls, such as the MX List and MX TileList controls, support item renderers or item editors. However, Flex provides the Spark List and Spark TileLayout class as replacements for the MX List and MX TileList controls. Always use the Spark components, when possible, in your application. There is no Spark equivalent for the MX DataGrid, MX AdvancedDataGrid, and MX Tree controls. Therefore, only those MX controls support the MXItemRenderer class.

About MX item renderers and item editors

All of the functionality of MX item renderers and item editors is supported by the MXItemRenderer class. Therefore, you should be familiar with the architecture of MX item renderers and editors before you create them based on the MXItemRenderer class.

Using the MXItemRenderer class

You base a Spark item renderer or item editor for an MX control on the MXItemRenderer class. While you can base an item renderer or editor on the MXItemRenderer class itself, you typically create them based on one of the following subclasses of MXItemRenderer:

Creating a Spark item renderer for an MX DataGrid control

The following application shows an MX DataGrid control that uses a custom item renderer:
<?xml version="1.0"?> 
<!-- itemRenderers\sparkmx\SparkMainDGImageRenderer.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    width="650"> 
    
    <fx:Script> 
        <![CDATA[ 
            import mx.collections.ArrayCollection; 
        
            [Bindable]                
            private var initDG:ArrayCollection = new ArrayCollection([ 
                {Artist:'Pavement', Album:'Slanted and Enchanted', 
                    Price:11.99, Cover: '../assets/slanted.jpg'}, 
                {Artist:'Pavement', Album:'Brighten the Corners', 
                    Price:11.99, Cover: '../assets/brighten.jpg'} 
            ]); 
        ]]> 
    </fx:Script> 
 
    <mx:DataGrid id="myGrid" height="400" width="600" 
        dataProvider="{initDG}">  
        <mx:columns> 
            <mx:DataGridColumn dataField="Artist"/> 
            <mx:DataGridColumn dataField="Album"/> 
            <mx:DataGridColumn dataField="Cover" 
                itemRenderer="myComponents.RendererDGImage"/> 
            <mx:DataGridColumn dataField="Price"/> 
        </mx:columns>       
    </mx:DataGrid>  
</s:Application>

In this example, you use the custom item renderer to display the album cover for each album listed in the DataGrid control. The Cover field of the data provider of the DataGrid contains the path to the JPG file for the cover.

Shown below is the definition of the RendererDGImage.mxml file that defines the item renderer:
<?xml version="1.0"?> 
<!-- itemRenderers\sparkmx\myComponents\RendererDGImage.mxml --> 
<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx"> 
 
        <mx:Image id="albumImage" height="175" source="{data.Cover}"/> 
</s:MXDataGridItemRenderer>

Notice that this item renderer is based on the MXDataGridItemRenderer class. The item renderer uses the Image control to display the album cover.

The next example also displays the album name and cover image, but uses a single column of the DataGrid to display both fields:
<?xml version="1.0"?> 
<!-- itemRenderers\sparkm\SparkMainDGTitleRenderer.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    width="650"> 
    
    <fx:Script> 
        <![CDATA[ 
            import mx.collections.ArrayCollection; 
        
            [Bindable]                
            private var initDG:ArrayCollection = new ArrayCollection([ 
                {Artist:'Pavement', Album:'Slanted and Enchanted', 
                    Price:11.99, Cover: '../../assets/slanted.jpg'}, 
                {Artist:'Pavement', Album:'Brighten the Corners', 
                    Price:11.99, Cover: '../../assets/brighten.jpg'} 
            ]); 
        ]]> 
    </fx:Script> 
 
    <mx:DataGrid id="myGrid" width="600" 
        dataProvider="{initDG}" 
        variableRowHeight="true">  
        <mx:columns> 
            <mx:DataGridColumn dataField="Artist" /> 
            <mx:DataGridColumn dataField="Album" 
                itemRenderer="myComponents.RendererDGTitleImage" /> 
            <mx:DataGridColumn dataField="Price"  /> 
        </mx:columns>       
    </mx:DataGrid>  
</s:Application>
The RendererDGTitleImage.mxml file implements the render. It uses a Spark Label control and the MX Image control to display the album name and cover image in a single cell:
<?xml version="1.0"?> 
<!-- itemRenderers\sparkmx\myComponents\RendererDGTitleImage.mxml --> 
<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"> 
    <s:layout> 
        <s:HorizontalLayout verticalAlign="middle" 
            paddingLeft="5" paddingRight="5"/> 
    </s:layout> 
 
    <s:Label id="albumName" 
        width="100%" 
        text="{data.Album}"/> 
    <mx:Image id="albumImage" 
        source="{data.Cover}"/>    
</s:MXDataGridItemRenderer> 

Creating a Spark item renderer for an MX AdvancedDataGrid control

The following application uses the AdvancedDataGrid control:
<?xml version="1.0"?> 
<!-- itemrenderers/sparkmx/SparkHierarchicalADGSimpleRenderer.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"> 
 
    <fx:Script> 
        <![CDATA[ 
              import mx.collections.ArrayCollection; 
                
              include "SimpleHierarchicalData.as"; 
        ]]> 
    </fx:Script> 
 
    <mx:AdvancedDataGrid width="100%" height="100%"> 
        <mx:dataProvider> 
            <mx:HierarchicalData source="{dpHierarchy}"/> 
        </mx:dataProvider> 
        <mx:columns> 
            <mx:AdvancedDataGridColumn dataField="Region"/> 
            <mx:AdvancedDataGridColumn dataField="Territory_Rep" 
                headerText="Territory Rep"/> 
            <mx:AdvancedDataGridColumn dataField="Actual"/> 
            <mx:AdvancedDataGridColumn dataField="Estimate"/> 
            <mx:AdvancedDataGridColumn id="diffCol" 
                headerText="Difference"/> 
        </mx:columns> 
 
        <mx:rendererProviders> 
            <mx:AdvancedDataGridRendererProvider column="{diffCol}" 
                depth="3" renderer="myComponents.SummaryRenderer"/> 
        </mx:rendererProviders> 
    </mx:AdvancedDataGrid> 
</s:Application>

This application uses the custom item renderer defined in the file SummaryRenderer.mxml to display the value of the Difference column. The value is determined by the difference between the Estimate and Actual columns. If the territory representative exceeded sales estimate, the cell appears in green. If the territory representative did not exceed the estimate, the cell appears in red.

The SummaryRenderer.mxml also includes a CurrencyFormatter to format the value in dollars. The SummaryRenderer.mxml is shown below:
<?xml version="1.0"?> 
<!-- itemrenderers/sparkmx/myComponents/SummaryRenderer.mxml --> 
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    textAlign="center"> 
    
    <fx:Script> 
        <![CDATA[ 
 
            override public function set data(value:Object):void 
            { 
                // Calculate the difference. 
                var diff:Number = 
                    Number(value["Actual"]) - Number(value["Estimate"]); 
                if (diff < 0) 
                { 
                    // If Estimate was greater than Actual, 
                    // display results in red. 
                    setStyle("color", "red"); 
                    myLabel.text = "Undersold by " + usdFormatter.format(diff); 
                } 
                else 
                { 
                    // If Estimate was less than Actual, 
                    // display results in green. 
                    setStyle("color", "green"); 
                    myLabel.text = "Exceeded estimate by " + usdFormatter.format(diff); 
                } 
            } 
        ]]> 
    </fx:Script> 
 
    <fx:Declarations> 
        <mx:CurrencyFormatter id="usdFormatter" precision="2" 
            currencySymbol="$" decimalSeparatorFrom="." 
            decimalSeparatorTo="." useNegativeSign="true" 
            useThousandsSeparator="true" alignSymbol="left"/> 
    </fx:Declarations> 
 
    <s:Label id="myLabel"/> 
</s:MXAdvancedDataGridItemRenderer>

Creating a Spark item renderer for an MX Tree control

The following application uses an MX Tree control to display XML data:
<?xml version="1.0" encoding="iso-8859-1"?> 
<!-- itemRenderers\tree\SparkMainTreeItemRenderer.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    initialize="initCollections();"> 
    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout> 
 
    <fx:Script> 
        <![CDATA[ 
   
            import mx.collections.*; 
    
            public var xmlBalanced:XMLList = 
                <> 
                    <node label="Containers"> 
                        <node label="DividedBoxClasses"> 
                            <node label="BoxDivider" data="BoxDivider.as"/> 
                        </node> 
                        <node label="GridClasses"> 
                            <node label="GridRow" data="GridRow.as"/> 
                            <node label="GridItem" data="GridItem.as"/> 
                            <node label="Other File" data="Other.as"/> 
                        </node> 
                    </node> 
                    <node label="Data"> 
                        <node label="Messages"> 
                            <node label="DataMessage" 
                                data="DataMessage.as"/> 
                            <node label="SequenceMessage" 
                                data="SequenceMessage.as"/> 
                        </node> 
                        <node label="Events"> 
                            <node label="ConflictEvents" 
                                data="ConflictEvent.as"/> 
                            <node label="CommitFaultEvent" 
                                data="CommitFaultEvent.as"/> 
                        </node> 
                    </node> 
                </>; 
                
            [Bindable] 
            public var xlcBalanced:XMLListCollection; 
    
            private function initCollections():void { 
                xlcBalanced = new XMLListCollection(xmlBalanced); 
            } 
        ]]> 
    </fx:Script> 
 
    <mx:Text width="400" 
        text="The nodes with children are in bold red text, with the number of children in parenthesis.)"/> 
 
    <mx:Tree id="compBalanced" 
        width="400" height="500" 
        dataProvider="{xlcBalanced}" 
        labelField="@label"  
        itemRenderer="myComponents.MyTreeItemRenderer"/> 
</s:Application>
This application uses the item renderer defined by the MyTreeItemRenderer.mxml file to display the parent nodes in a red, bold font. It also shows the number of child nodes for each parent in parenthesis. Shown below is the definition of MyTreeItemRenderer.mxml:
<?xml version="1.0" encoding="utf-8"?> 
<!-- itemRenderers\sparkmx\myComponents\MyTreeItemRenderer.mxml --> 
<s:MXTreeItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"> 
    
    <fx:Script> 
        <![CDATA[ 
 
            import mx.controls.treeClasses.*; 
            import mx.collections.*; 
            
            // Override the set method for the data property 
            // to set the font color and style of each node.        
            override public function set data(value:Object):void { 
                super.data = value; 
                if(treeListData.hasChildren) 
                { 
                    setStyle("color", 0xff0000); 
                    setStyle("fontWeight", 'bold'); 
                    var tmp:XMLList = 
                        new XMLList(treeListData.item); 
                    var myStr:int = tmp[0].children().length(); 
                    labelDisplay.text =  treeListData.label + 
                        "(" + myStr + ")"; 
                } 
                else 
                { 
                    setStyle("color", 0x000000); 
                    setStyle("fontWeight", 'normal'); 
                    labelDisplay.text =  treeListData.label; 
                }  
            } 
        ]]> 
    </fx:Script> 
    
    <s:HGroup left="0" right="0" verticalCenter="0"> 
        <s:Rect id="indentationSpacer" 
            width="{treeListData.indent}" height="22" 
            alpha="0"> 
            <s:fill> 
                <s:SolidColor color="0xFFFFFF" /> 
            </s:fill> 
        </s:Rect> 
        <s:Group id="disclosureGroup"> 
            <s:BitmapImage source="{treeListData.disclosureIcon}" 
                width="16" height="16" 
                visible="{treeListData.hasChildren}" /> 
        </s:Group> 
        <s:BitmapImage source="{treeListData.icon}" 
            width="16" height="16"/> 
        <s:Label id="labelDisplay" /> 
    </s:HGroup> 
</s:MXTreeItemRenderer>

The item renderer uses the treeListData property of the MXTreeItemRenderer class to determine the information about the tree node. The treeListData property is of type TreeListData. TreeListData defines information such as the depth of the node in the tree, any icon associated with the node, and the data object of the node from the tree's data provider.

This item renderer overrides the ItemRenderer.data property to control the display of the tree nodes. The override first determines if the node is a parent node and, if so, sets the text display to use a bold, red font. It then adds the number of children to the display of the node.

The second part of the item renderer defines the appearance of the node in the Tree control. In this example, you use a Rect control to define a white background for the node. The item renderer uses two BitmapImage controls to define the appearance of any icons. The Label control defines the appearance of the text displayed by the node.

Creating a Spark item editor for an MX DataGrid control

An MX DataGrid, AdvancedDataGrid, or Tree control displays an item editor when the editable property of the control is set to true. The item editor appears when the user releases the mouse button while over a cell, tabs to the cell, or in another way attempts to edit the cell. By default, the editable property is false.

When creating an item editor for an MX DataGrid or Tree control, the item editor usually returns a single value corresponding to the new value in the control's data provider. For example, the following item renderer returns a single value named myRetValue:
<?xml version="1.0"?> 
<!-- itemRenderers\sparkmx\myComponents\NSEditor.mxml --> 
<s:MXDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"> 
    
    <fx:Script> 
        <![CDATA[ 
            public var myRetVal:int = 0; 
        ]]> 
    </fx:Script> 
    
    <!-- Use the valueCommit event when the user selects the 
         cell but does not change the value. --> 
    <s:NumericStepper id="myNS" 
        value="{data.quant}" 
        stepSize="1" 
        maximum="50" 
        change="myRetVal=myNS.value;" 
        valueCommit="myRetVal=myNS.value;"/> 
</s:MXDataGridItemRenderer>

This item editor contains a single NumericStepper control. When the item editor is open, the NumericStepper appears in the DataGrid control. The user can then use the NumericStepper to edit the value of the cell.

The user ends the editing session by removing focus from the cell. Flex then commits the new value in the DataGrid control. The following application uses this item editor:
<?xml version="1.0"?> 
<!-- itemRenderers\sparkmx\SparkMainNSEditor.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"> 
     
    <fx:Script> 
        <![CDATA[ 
            import mx.collections.ArrayCollection; 
        
            [Bindable] 
            private var myDP:ArrayCollection = new ArrayCollection([ 
                {label1:"Order #2314", quant:3, Sent:true}, 
                {label1:"Order #2315", quant:3, Sent:false}     
            ]);               
        ]]> 
    </fx:Script> 
 
    <mx:DataGrid id="myDG" dataProvider="{myDP}" 
            variableRowHeight="true" 
            editable="true" > 
        <mx:columns> 
            <mx:DataGridColumn dataField="label1" 
                headerText="Order #"/> 
            <mx:DataGridColumn dataField="quant" 
                itemEditor="myComponents.NSEditor" 
                editorDataField="myRetVal"/> 
        </mx:columns > 
    </mx:DataGrid> 
</s:Application>

Notice in the main application that the DataGridColumn uses the itemEditor property to specify the name of the item editor. It uses the editorDataField property to specify the name of the property of the item editor that contains the return value.

Creating an inline Spark item editor for an MX DataGrid control

An MX DataGrid, AdvancedDataGrid, or Tree control can use an inline item renderer or editor. The following example uses a Spark DropDownList control as the item editor for a column of an MX DataGrid control:
<?xml version="1.0"?> 
<!-- itemRenderers\sparkmx\SparkDGInlineRenderer.mxml --> 
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    width="650"> 
    
    <fx:Script> 
        <![CDATA[ 
            import mx.collections.ArrayCollection; 
            
            [Bindable]                
            private var initDG:ArrayCollection = new ArrayCollection([ 
                {Artist:'Pavement', Album:'Slanted and Enchanted', 
                    Price:11.99, Cover: '../assets/slanted.jpg', Rating:'none'}, 
                {Artist:'Pavement', Album:'Brighten the Corners', 
                    Price:11.99, Cover: '../assets/brighten.jpg', Rating:'none'} 
            ]); 
        ]]> 
    </fx:Script> 
 
    <mx:DataGrid id="myGrid" height="400" width="600" 
        dataProvider="{initDG}" editable="true">  
        <mx:columns> 
            <mx:DataGridColumn dataField="Artist"/> 
            <mx:DataGridColumn dataField="Album"/> 
            <mx:DataGridColumn dataField="Rating" editorDataField="rating"> 
                <mx:itemEditor> 
                    <fx:Component> 
                        <s:MXDataGridItemRenderer focusEnabled="true" height="22" > 
                            <fx:Script> 
                                <![CDATA[ 
                                    import mx.collections.ArrayList; 
                                    
                                    public function get rating():String { 
                                        return  dd.selectedItem; 
                                    } 
                                ]]> 
                            </fx:Script> 
                            <s:DropDownList id="dd" top="5" left="5" 
                                selectedItem="{data.Rating}" 
                                initialize="dd.dataProvider = 
                                    new ArrayList(['none', 'no good', 'good', 'great'])"/> 
                        </s:MXDataGridItemRenderer> 
                    </fx:Component> 
                </mx:itemEditor> 
            </mx:DataGridColumn> 
            <mx:DataGridColumn dataField="Cover" 
                itemRenderer="myComponents.RendererDGImage"/> 
            <mx:DataGridColumn dataField="Price"/> 
        </mx:columns>       
    </mx:DataGrid>  
</s:Application>

This example adds a Rating column to the DataGrid. The user clicks in a cell of the Rating column to open the item editor. When the user removes focus from the cell, the value of the DropDownList is copied to the data provider of the DataGrid.

Navigation

Using Flex » Building the user interface

Adobe and Adobe Flash Platform are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries and are used by permission from Adobe. No other license to the Adobe trademarks are granted.