Using Spark list-based controls

The Spark list-based controls include the following:

The Spark list-based controls are all subclasses of the SkinnableDataContainer and ListBase classes. The SkinnableDataContainer class is designed to display data items by using item renderers. Data items can be simple data types, such as String and Number objects, or more complex data types such as Object and XMLNode objects.

The ListBase class is a subclass of the SkinnableDataContainer class. The ListBase class adds support for item selection in the list of data items, and for controlling the text displayed in the list. The ButtonBar, ComboBox, DropDownList, List, and TabBar controls add additional functionality to the ListBase class.

For more information on SkinnableDataContainer, and on creating item renderers, see The Spark DataGroup and Spark SkinnableDataContainer containers.

Defining the children of a list-based control

The list-based controls are examples of data provider components. Data provider components require data for display or user interaction. To provide data, assign a collection which implements the IList interface, such as an ArrayList, ArrayCollection, or XMLListCollection object, to the control’s dataProvider property. For more information on using data providers, see Data providers and collections.

Data items can be simple data items such as String and Number objects, and more complicated data items such as Object and XMLNode objects. The following example shows a List control that displays data items represented by String data:

<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListSimple.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">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <s:List> 
        <s:dataProvider>
            <mx:ArrayCollection>
                <fx:String>Flash</fx:String> 
                <fx:String>Director</fx:String> 
                <fx:String>Dreamweaver</fx:String> 
                <fx:String>ColdFusion</fx:String> 
            </mx:ArrayCollection>
         </s:dataProvider>
    </s:List>
</s:Application>

The executing SWF file for the previous example is shown below:

For simple data items, such as Strings and Numbers, the controls display the entire data item as a String. For more complicated data items, such as Objects, you can control the text displayed in the control based on the data item. For more information, see Controlling the text displayed for each data item.

Because dataProvider is the default property of the list-based controls, you do not have to specify a <s:dataProvider> child tag. Therefore, you can write the example as shown below:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListSimpleNoDP.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">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <s:List> 
        <mx:ArrayCollection>
            <fx:String>Flash</fx:String> 
            <fx:String>Director</fx:String> 
            <fx:String>Dreamweaver</fx:String> 
            <fx:String>ColdFusion</fx:String> 
        </mx:ArrayCollection>
    </s:List>
</s:Application>

The executing SWF file for the previous example is shown below:

Controlling the text displayed for each data item

The following example shows a List control where each data item is represented by an Object with three fields:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListSimpleObjects.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">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <s:List id="myList"
        labelField="firstName">
        <mx: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"/>
        </mx:ArrayCollection>
    </s:List>
</s:Application>

The executing SWF file for the previous example is shown below:

When the data items contains multiple fields, you must configure the control to display the correct String. In the previous example, you use the labelField property to specify to display the firstName field in the control.

You can use several different mechanisms for controlling the String displayed by the control:
  • Use the labelFunction property

    The labelFunction property lets you define a function that returns a String for display by the control. By default, the labelFunction property takes precedence over the labelField property.

  • Use the labelField property

    The labelField property specifies the field of the data item to display in the control.

  • Override the itemToLabel() method

    Override the itemToLabel() method to convert the data item to a String that is then passed to an item renderer. This method is defined on the SkinnableDataContainer class.

    By default, itemToLabel() prioritizes labelFunction over labelField. If you override itemToLabel(), you can implement it however you like. Your implementation can then choose to use or ignore labelField and labelFunction. For an example that overrides this method, see Passing data using the IItemRenderer.label property.

When you use the labelFunction property, you define a function that calculates the String to display. Typically, the String is derived from the fields of the data item. The label function must have the following signature:

labelFunction(item:Object):String

The item parameter contains the data item. The function must return a String.

The following example uses a label function to concatenate the firstName and lastName fields of each data item for display by the control:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListSimpleObjectsLF.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">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <fx:Script>
        <![CDATA[
            public function myLabelFunc(item:Object):String {
                return item.firstName + " " + item.lastName; 
            }
        ]]>
    </fx:Script>

    <s:List id="myList"
        labelFunction="myLabelFunc">
        <mx: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"/>
        </mx:ArrayCollection>
    </s:List>
</s:Application>

The executing SWF file for the previous example is shown below:

Modifying the children of a list-based control

A list-based control creates list items based on the value of its dataProvider property. Typically, the control creates one list item for each data item. For example, the List control creates one list item for each data item, and the ButtonBar control creates one button for each data item.

Use the addItem() and removeItem() methods to manipulate the dataProvider property. A ButtonBar control automatically adds or removes children based on changes to the dataProvider property, as the following example shows:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkBBarSimpleModDP.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">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    
    <fx:Script>
        <![CDATA[
            // Add data item, and button, to the ButtonBar.
            private function addFlexToDP():void {
                myBB.dataProvider.addItem("Flex");
                addFlex.enabled=false;
                removeFlex.enabled=true;
            }

            // Remove data item, and button, from the ButtonBar.
            private function removeFlexToDP():void {
                myBB.dataProvider.removeItemAt(4);
                addFlex.enabled=true;
                removeFlex.enabled=false;
            }
        ]]>
    </fx:Script>

    <s:ButtonBar id="myBB">  
        <mx:ArrayCollection>
            <fx:String>Flash</fx:String> 
            <fx:String>Director</fx:String> 
            <fx:String>Dreamweaver</fx:String> 
            <fx:String>ColdFusion</fx:String> 
        </mx:ArrayCollection>
    </s:ButtonBar>
    
    <s:Button id="addFlex" label="Add Flex"
        click="addFlexToDP();"/>
    <s:Button id="removeFlex" label="Remove Flex"
        enabled="false"
        click="removeFlexToDP();"/>
</s:Application>

The executing SWF file for the previous example is shown below:

Setting the layout

The list-based controls support the layout property to let you control the layout of the data items. For example, the default layout of the List control is VerticalLayout. You can use any of the Flex layout classes with the list-based controls, and any custom layouts that you create.
Note: The Spark list-based controls do not support the BasicLayout class. Do not use BasicLayout with the Spark list-based controls.

The following example overrides that layout to use TileLayout:

<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListLayout.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">
         
    <s:List width="200">
        <s:layout>
            <s:TileLayout/>
        </s:layout>
        <mx:ArrayCollection>
            <fx:String>Flex</fx:String> 
            <fx:String>Flash Builder</fx:String> 
            <fx:String>Flash</fx:String> 
            <fx:String>Director</fx:String> 
            <fx:String>Dreamweaver</fx:String> 
            <fx:String>ColdFusion</fx:String> 
            <fx:String>Illustrator</fx:String> 
        </mx:ArrayCollection>
    </s:List> 
</s:Application>

The executing SWF file for the previous example is shown below:

For more information on Spark layouts, see About Spark layouts.

Working with list events

The list-based classes all support the following events:
  • caretChange Dispatched after the focus has changed from one data item to another. For more information, see Working with the caret item.

  • change Dispatched after the currently selected data item changes to another data item. This event is dispatched when the user interacts with the control.

    When you change the value of the selectedIndex or selectedItem properties programmatically, the control does not dispatch the change event. It dispatches the valueCommit event instead.

    For more information, see Working with the selected item.

  • changing Dispatched before the currently selected data item changes. This event is dispatched when the user interacts with the control.

    Calling the preventDefault() method in the event handler prevents the selection from changing. This event is useful when you want to perform processing on the currently selected item before selection moves to a new data item, or to prevent an item from being selected.

    When you change the value of the selectedIndex or selectedItem properties programmatically, it does not dispatch the changing event. It dispatches the valueCommit event instead.

The event object for all events is spark.events.IndexChangeEvent.

Working with the selected item

The ListBase class adds support for item selection in the list of data items, and for controlling the text displayed in the list. Several properties of the ListBase class handle the selection of a data item in the control. These properties include the following:

  • requireSelection Specifies that a data item must always be selected. The default is false. If true, then the first data item is selected by default until the user selects a list item, or until you set the selectedIndex property.

  • selectedIndex The index of the currently selected data item. The index of items in the list-based controls is zero-based, which means that values are 0, 1, 2, ... , n - 1, where n is the total number of items. If requireSelection is false, you can also set selectedIndex to -1 to deselect all data items.

  • selectedItem The object from the data provider corresponding to the currently selected data item.

You often use these properties in event handlers, as the following example shows for the change event. In this example, the List control displays the firstName field of each data item. When you select a data item in the control, the event handler for the change event displays the index and the lastName field of the data item in TextArea controls.

<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListSelected.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"
    height="450">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    
    <fx:Script>
        <![CDATA[
            import spark.events.IndexChangeEvent;

            protected function selectionChangedHandler(event:IndexChangeEvent):void
            {
                var currentIndx:int = event.currentTarget.selectedIndex;
                var currentDataItem:Object = event.currentTarget.selectedItem;
                selIndex.text = String(currentIndx);
                selLName.text = String(currentDataItem.lastName);
            }

        ]]>
    </fx:Script>
         
    <s:List id="myList"
        labelField="firstName" 
        change="selectionChangedHandler(event)">
        <mx: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"/>
        </mx:ArrayCollection>
    </s:List>
    
    <s:Label text="Selected index:"/>
    <s:TextArea id="selIndex" height="50"/>

    <s:Label text="Selected Last Name:"/>
    <s:TextArea id="selLName" height="50"/>
    
</s:Application>

The executing SWF file for the previous example is shown below:

The currentTarget property of the object passed to the event handler contains a reference to the List control. Therefore, the currentTarget.selectedIndex field contains the index of the selected item, and the currentTarget.selectedItem field contains a copy of the selected item.

Working with the caret item

The selected item is the item in the control selected by clicking on the item, or by using the arrow keys. For more information about determining the selected item, see Working with the selected 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.

You use the caretIndex property to determine the index of the data item that currently has focus. The index is zero-based, which means that values are 0, 1, 2, ... , n - 1, where n is the total number of items.

The following example displays the selectedIndex and the caretIndex properties for a List control:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListCaret.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">
    <s:layout>
        <s:VerticalLayout paddingTop="5" paddingLeft="5"/>
    </s:layout> 

    <s:Label text="The selected item is: {myList.selectedIndex}" />
    <s:Label text="The caret item is: {myList.caretIndex}" />

    <s:List id="myList">
        <s:dataProvider>
            <s:ArrayCollection>
                <fx:String>One</fx:String>
                <fx:String>Two</fx:String>
                <fx:String>Three</fx:String>
                <fx:String>Four</fx:String>
                <fx:String>Five</fx:String>
                <fx:String>Six</fx:String>
                <fx:String>Seven</fx:String>
                <fx:String>Eight</fx:String>
                <fx:String>Nine</fx:String>
                <fx:String>Ten</fx:String>
            </s:ArrayCollection>
        </s:dataProvider>
    </s:List>
</s:Application>

The executing SWF file for the previous example is shown below:

To see the difference between the selectedIndex and the caretIndex properties:

  1. Select an item in the List control by clicking on it. Notice that because the item is both selected and in focus that the selectedIndex and the caretIndex properties have the same value.

  2. Use the Up Arrow and Down Arrow keys to move the selected item. Notice that because the item is both selected and in focus that the selectedIndex and the caretIndex properties have the same value.

  3. With an item selected:

    • (On Windows) Hold down the Control key, and then use the Up Arrow and Down Arrow keys to move the caret index.

    • (On OSX) Hold down the Command key, and then use the Up Arrow and Down Arrow keys to move the caret index.

    Notice that the List control displays a blue box around the data item at the caret index, but the index of the selected item does not change. The data item at the caret index has focus, but is not selected. Press the Space key to select the data item at the caret index.

The list-based controls dispatch the caretChange event when the caret item changes.

Working with item renderers

Because the list-based classes are subclasses of the SkinnableDataContainer class, they require an item renderer to display the data items. The SkinnableDataContainer class does not define a default item renderer. However, the list-based classes all define a default item render as the following table shows:

Control

Default item renderer

ButtonBar

ButtonBarButton

ComboBox

DefaultItemRenderer

DropDownList

DefaultItemRenderer

List

DefaultItemRenderer

TabBar

ButtonBarButton with TabBarButtonSkin as the skin

You can override the default item renderer. For more information, see Using an item renderer function with a Spark container.

Using virtualization with list-based controls

A list-based control can represent any number of children. However, each child requires an instance of an item renderer. If the container has many children, you can notice performance degradation as you add more children to the container.

Instead of creating an item renderer for each child, you can use the useVirtualLayout property to configure the control to use a virtual layout. With virtual layout enabled, the control reuses item renderers so that it only creates item renderers for the currently visible children of the container. As a child is moved off the screen, possible by scrolling the container, a new child being scrolled onto the screen can reuse its item renderer.

The layout class associated with a component determines if the component supports virtual layout. Typically, you use the component’s skin class to specify the layout class. By default, the skins for the Spark list-based classes have the useVirtualLayout property to true to enable virtual layout.

However, the default skins of some components use layouts that do not support the useVirtualLayout property. The TabBar and ButtonBar components use the ButtonBarHorizontalLayout which does not support the useVirtualLayout property or virtual layout.

For more information on virtualization, see Using virtualization with Spark DataGroup and SkinnableDataContainer.

Supporting view states in an item renderer for a list-based control

The Spark list-based controls support view states that you can use in a custom item renderer. Support for these view states is not required. If the host component attempts to set the item renderer to a view state that is not defined in the renderer, then the item renderer uses the normal view state.

Flex defines the following view states for 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 selected state, and it has focus in the item list.

The default item renderers, including DefaultItemRenderer and DefaultComplexItemRenderer, support all of these view states.

The list-based controls add the ability to select a data item. Therefore, one of the view states corresponds to the data item being selected. The item renderer can use the selected view state to modify the appearance of the item when selected.

Several view states are associated with the caret index. The caret index identifies the data item that has focus. That item does not have to be the selected item,

The following example shows a simple item renderer for the List class that supports the selected view state. In this example, the item renderer shows the selected item in red with a black border:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer 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[
            
            override public function set label(value:String):void {
                super.label = value;
                labelDisplay.text = label; 
            }
        ]]>
    </fx:Script>

    <s:states>
        <s:State name="normal"/>
        <s:State name="hovered"/>
        <s:State name="selected"/>
    </s:states>
    
    <s:Rect left="0" right="0" top="0" bottom="0">
        <s:stroke.selected>
            <s:SolidColorStroke 
                color="0x000000" 
                weight="1"/>
        </s:stroke.selected>
        <s:fill>
            <s:SolidColor 
                color.normal="0xFFFFFF"
                color.hovered="0xCEDBEF" 
                color.selected="0x00FF00"/>
        </s:fill>
    </s:Rect>
    <s:Label id="labelDisplay" 
        fontWeight.selected="bold"
        verticalCenter="0" 
        left="3" right="3" 
        top="6" bottom="4"/>
</s:ItemRenderer>

This item renderer does not define all possible view states. If the host component attempts to set it to any undefined view state, the item renderer uses the normal state.

The following application uses this item renderer:
<?xml version="1.0" encoding="utf-8"?>
<!-- dpcontrols\sparkdpcontrols\SparkListIR.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">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

    <s:List itemRenderer="myComponents.ListSelectedIR"> 
        <s:dataProvider>
            <mx:ArrayCollection>
                <fx:String>Flash</fx:String> 
                <fx:String>Director</fx:String> 
                <fx:String>Dreamweaver</fx:String> 
                <fx:String>ColdFusion</fx:String> 
            </mx:ArrayCollection>
         </s:dataProvider>
    </s:List>
</s:Application>

The executing SWF file for the previous example is shown below:

Using a mobile item renderer with a Spark list-based control

Flex provides two item renderers that you can use with Spark list-based controls in mobile applications. These item renderers, spark.components.LabelItemRenderer and spark.components.IconItemRenderer, are written in ActionScript to provide the highest level of performance required by mobile applications.

The default theme for mobile applications built in Flex is the Mobile theme. When you use the Mobile theme, Flex automatically uses the LabelItemRenderer for the Flex list-based controls. Like the DefaultItemRenderer, the LabelItemRenderer displays a single text field for each data item.

You can use the IconItemRenderer in a mobile application. The IconItemRenderer displays two text fields, one above the other, and two icons for every data item.

The following example shows a List control defined in the view of a mobile application. In this example, the List control uses the IconItemRenderer to display the first name, last name, and an icon for every data item in the list:
<?xml version="1.0" encoding="utf-8"?>
<!-- containers\mobile\views\ContactsMobileIconIR.mxml -->
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    title="Contacts View Main">
    <s:layout>
        <s:VerticalLayout paddingTop="10"/>
    </s:layout>
    
    <fx:Style>
        @namespace s "library://ns.adobe.com/flex/spark";
        .myFontStyle { 
            fontSize: 15;
            color: #9933FF;
        }

    </fx:Style>
    
    <s:Label text="Select a contact name"/>
    <s:List id="myList"
        width="100%" height="100%"
        labelField="firstName">
        <s:itemRenderer>
            <fx:Component>
                <s:IconItemRenderer messageStyleName="myFontStyle" fontSize="25"
                    labelField="firstName"
                    messageField="lastName" 
                    decorator="@Embed(source='../assets/logo_small.jpg')"/>
            </fx:Component>
        </s:itemRenderer>
        <s:ArrayCollection>
            <fx:Object firstName="Dave" lastName="Duncam" company="Adobe" phone="413-555-1212"/>
            <fx:Object firstName="Sally" lastName="Smith" company="Acme" phone="617-555-1491"/>
            <fx:Object firstName="Jim" lastName="Jackson" company="Beta" phone="413-555-2345"/>
            <fx:Object firstName="Mary" lastName="Moore" company="Gamma" phone="617-555-1899"/>
        </s:ArrayCollection>
    </s:List>
</s:View>