在 DAtaGroup , SkinnableDataContainer 或它們的子類中定義自己的項目渲染器可以控制數據項的顯示外觀,數據項的外觀包括字體、背景色、邊界和其他的可視方面。項目渲染器也可以在和用户進行交互的時候指定要顯示的外觀。例如,用户鼠標移動到數據項上時顯示一種外觀,當用户點擊時顯示另一種外觀。Spark 項目渲染器的基類 ItemRenderer 已經內置支持了所有用户要進行交互。缺省項目渲染器 DefaultItemRenderer 和 DefaultComplexItemRenderer 支持這些用户的交互操作。在你自定義的項目渲染器中,你可以選擇依賴 ItemRenderer 類支持的缺省交互支持還是實現你自己的交互。許多 Spark 組件既支持皮膚也支持項目渲染器。當項目渲染器定義了數據項的外觀,皮膚定義了組件完整的可視化外觀。皮膚可以包含邊界、滾動條和組件外觀的其他方面。

item 渲染器的架構

為了更好的理解項目渲染器是如何工作的和查閲自定義項目渲染器是如何實現的,請看下面的代碼。下面的代碼演示了給 SkinnableDataContainer 容器自定義的項目渲染器,這段代碼的作用是當鼠標移動到控件上時,數據項的字體顏色改變。

<?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>

所有項目渲染器的基類是 ItemRenderer 類,此類是 Group 類的子類,所以它本身也是一個容器。在 ItemRenderer 類的內部定義了佈局、狀態和用於顯示數據項的子控件。

ItemRenderer 類的缺省佈局是 BasicLayout 。在這個實例中,由於沒有指定 Layout 屬性,本項目渲染器仍然使用 BasicLayout 。

項目渲染器也可以定義視圖的狀態。所有的視圖狀態都是可選的。在本實例中,你可以處理 normal 和 hovered 視圖狀態。 normal 狀態定義了數據項在沒有和用户進行交互時顯示的外觀,而 hovered 狀態定義了鼠標移動到數據項時的外觀。

本實例使用 hovered 視圖狀態來更改用户將鼠標移動到數據項時的字體,字體被更改為 14 point 、斜體。關於在項目渲染器中使用視圖的狀態更多的信息請參考 為 Spark容器定義項目渲染器的視圖狀態 。

Label 控件被居中垂直顯示在項目渲染器的顯示區域,它距離左邊界的距離限制為 3 個像素,距離上邊界 6 個像素,距離底邊界 4 個像素。你可以在自己的項目中通過模仿上面的代碼,在你自己的項目渲染器中使用這些設置,或者在必要的時候更改這些設置。

在項目渲染器中 Label 控件的 id 是 labelDisplay 。在一個項目渲染器中這是一個指定命名的組件。 Flex 寫表示數據的字符串將會寫入到 labelDisplay 組件中。 Flex 也使用labelDisplay 組件來決定在宿主組件中 baselinePosition 數據的值。

下面的應用使用了這個自定義項目渲染器:

<?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>

在一個項目渲染器中控制一個數據項目的背景色

ItemRenderer 類定義了所有用户交互時的缺省背景顏色,當沒有用户交互時項目渲染器缺省畫一個透明的背景色。當用户碰到它時會畫一個淺藍色的背景。

有些子類,例如: DataGroup 、 SkinnableDataContainer 的子類 List 支持更多的用户交互。例如: List 控件支持數據項的選擇。當用户選擇了一個數據項,項目渲染器缺省畫一個深藍色的背景色。

當用户定義定義了自己的項目渲染器時,你可以選擇使用缺省的背景色還是定義自己的。如果使用缺省的,你的項目渲染器將顯示和缺省項目渲染器相同的外觀。

ItemRenderer 類使用 CSS 樣式來定義不同的視圖狀態。你可以通過更改 contentBackgroudColor 、 selectionColor 的值來制定渲染器的缺省顏色。例如:

l         contentBackgroundColor = 0xFFFFFF (white)
l         rollOverColor = 0xCEDBEF
l         selectionColor = 0xA8C6EE

這些顏色定義在 spark..swc 的 default.css 文件中如果你想要自己的項目渲染器模仿 Flex 的設置,在自己的項目渲染器中使用相同的設置。

下面的示例展示瞭如何設置 rollOverColor 樣式為綠色:

<?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>

如果要完全控制項目渲染器的背景色,需要將 ItemRenderer.autoDrawBackground 屬性設置為 false 。此屬性設置為 false 後,你自己的項目渲染器負責顯示所有用户交互的背景色。

下面代碼展示了將 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>

這個示例重寫了 ItemRenderer 類的 itemIndex 屬性。 itemIndex 屬性包含有數據項在宿主組件的數據提供者中的索引值,重寫它會設置奇數行背景色為綠色,偶數行背景色為白色。

下面的代碼展示瞭如何引用上面的項目渲染器:

<?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>

將參數傳遞給 Spark 項目渲染器中

項目渲染器的宿主組件稱之為項目渲染器的擁有者。項目渲染器的基類 ItemRenderer 定義了幾個屬性,宿主組件可以通過它們將一些信息傳遞給當前渲染器。

       label   表示數據項的字符串。原始的數據項要麼是一個字符串要麼是項目渲染器的擁有者將數據項轉換為一個字符串。

       data   原始的數據項

       owner   項目渲染器的宿主,例如:如果 SkinnableDataContainer 是一個項目渲染器的擁有者,那麼可以通過 ItemRenderer.owner 屬性來訪問它。

       dragging   如果該渲染器可以拖拽則值為 true 。

       itemIndex   在宿主組件的數據提供者中的索引值。

       selected   如果項目渲染器本身可以顯示為選中則值為 true 。例如 Spark List 控件可以進行選中,但是 DataGroup 容器就不能被選擇。

       showCaret   如果項目渲染器本身可以被設置焦點則值為 true 。

項目渲染器的宿主必須實現 IItemRendererOwner 接口。此接口定義了下面這些方法,以便項目渲染器可以將必要的信息寫入裏面。

itemToLabel() ——將數據項轉換為字符串表達式。組件可以重寫此方法來定義自己的字符串轉換。

updateRenderer() ——將數據項作為字符串寫入到 ItemRenderer.label 屬性中。更新 ItemRenderer.owner 屬性中的宿主組件。此方法的最後一件事是設置項目渲染器的數據屬性。組件可以重寫此方法以便將一些額外的信息傳遞給項目渲染器。

在你建立自定義的項目渲染器之前,需要決定如何將數據項傳遞給項目渲染器。在某些情況中,你在傳遞數據給項目渲染器之前需要進行一些數據項的處理。如果是這樣,需要在宿主組件中重寫 itemToLabel() 和 updateRenderer() 方法。項目渲染器之後就可以通過 label 屬性來訪問數據了。

如果不是宿主組件處理數據項而是項目渲染器來執行處理。使用 ItemRenderer.data 屬性傳遞數據項。項目渲染器之後可以訪問 data 屬性並在顯示數據之前執行必要的處理。

重寫 itemToLabel() 和 updateRenderer() 的示例參考 使用 ItemRenderer.label屬性傳遞參數 。使用 data 屬性的示例參考 使用 ItemRenderer.data屬性傳遞數據 。

使用 ItemRenderer.lable 屬性傳遞數據

如果數據項是一個字符串或者值,它可以很容易的轉換為字符串。你可以使用ItemRenderer.label 屬性傳遞給項目渲染器。如果數據項必須轉換為字符表達式,可以重寫宿主組件中的itemToLabel() 方法來定義自己的轉換。

下面示例中,SkinnableDataContainer 容器中的子元素根據字符串定義不同的顏色。

<?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>

這個示例使用了叫 MySimpleColorRenderer 的自定義項目渲染器。該渲染器定義在 MySimpleColorRenderer.mxml 文件中,它的作用是根據文本字符串顯示相應的背景色。

<?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>

在這個示例中,項目渲染器重新賦值了 label 屬性,將顏色值寫入 Label 控件中,並填充 Rect 組件的顏色。

項目渲染器顯示數據並不是基於狀態的改變。因此,需要設置 ItemRenderer.autoDrawBackground 的屬性為 false 。這個項目渲染器用於顯示沒有其他用户交互功能的數據。如果要顯示基於用户交互而顯示更改的示例參見: 為配合 Spark容器給項目渲染器定義狀態 。

如果要修改傳遞給 label 屬性的字符串,需要重寫宿主組件中的 itemToLabel() 方法。該方法的格式如下:

itemToLabel(item:Object):String

該方法有一個參數表示數據項。它返回要顯示在數據渲染器中的字符串。

下面示例中每一個數據項由三個部分組成。自定義的 MyDAtaGroup 組件重寫了 itemToLabel() 方法,該方法將對象進行格式化然後傳遞字符串給項目渲染器。這個示例使用了DefaultItemRenderer 來顯示文本。

<?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>

MyDataGroup.mxml 文件自定義了 SkinnableDataContainer 容器,它重寫了 itemToLabel ()方法。

<?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>

使用 ItemRenderer.data 屬性傳遞數據

有時不需要在宿主組件中處理數據而是在項目渲染器自己來處理所有的數據項的顯示,在這種情況下, ItemRenderer.data 屬性用於將數據傳遞給項目渲染器。有了這個技術,你就可以定義一組項目渲染器用來以不同的方式顯示相同的數據。

下一個示例中,每一個數據項由一個對象來表示,它包含了三個部分:

<?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>

SkinnableDataContainer 使用自定義的項目渲染器 MySimpleColorRenderer 。該渲染器將 firstName 和 lastName 顯示在一個單獨的 label 組件,將 companyID 顯示在另一個label 組件中:

<?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>

data 屬性包含了傳遞給 DataGroup 組件的對象,該對象以原始的狀態表示數據項。渲染器使用數據綁定來將控件和數據進行關聯。兩個 Label 組件定義在和 Group 容器中以便它們可以水平顯示。

如果使用數據綁定,亦可以在項目渲染器中重寫數據屬性,使用重寫你可以修改 data 或執行其他處理,這些是在 set 屬性中完成。下面的示例展示瞭如何重寫 data 屬性。

<?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>

為配合 Spark 容器給項目渲染器定義狀態

項目渲染器支持任意的視圖狀態。 Flex 定義一些默認的狀態如下所示:

         normal   不需要用户交互的數據狀態

         hovered   當鼠標懸停在數據項時 .

         selected   當該數據項被選中時

         dragging   當該數據項被拖拽時

         normalAndShowCaret   數據項時 normal 狀態,且在項目列表中處於焦點狀態

         hoveredAndShowCaret   數據項處於懸停狀態,且在項目列表中處於焦點狀態

         selectedAndShowCaret   該數據項處於 normal 狀態,且在項目列表中處於焦點狀態

當用户和控件進行交互時,更改了項目渲染器的視圖狀態, Flex 首先要確定該項目渲染器是否定義了該視圖狀態。如果定義了, Flex 設置項目渲染器使用該狀態。如果沒有定義,則忽略。

selected, normalAndShowCaret, hoveredAndShowCaret, and selectedAndShowCaret 這些視圖狀態由基於 list 的組件支持。基於 list 的組件是spark.components.supportClasses.ListBase 的子類。 DataGroup 和 SkinnableDataContainer 容器並沒有實現這些視圖狀態。

DefaultItemRenderer 和 DefaultComplexItemRenderer 容器支持所有的視圖狀態。所以你可以在基於 list 的組件中使用這些渲染器。

你的項目渲染器支持的視圖狀態根據每種視圖狀態的改變執行相應的動作。例如,你可以根據視圖狀態的更改來變化顯示的內容或不變化。你也可以定義額外的視圖狀態。

下面的示例,你可以了 SkinnableDataContainer 容器來顯示一個有四個屬性的對象: lastName 、 firstName 、 companyID 和 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>

下面這個項目渲染器顯示了在懸停狀態的文本為粗體、藍色字體:

<?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>

因為 SkinnableDataContainer 容器不支持 selected 視圖狀態,項目渲染器沒有設定 selected 狀態的任何定義。

也可以在項目渲染器中包含一個變幻。一旦你改變了視圖狀態,開始演示該變幻。下面的項目渲染器使用一個變幻來演示鼠標飛過該項目時的 companyID 和 telephone 。

<?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>

下面的示例使用了上面的項目渲染器:

<?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>


和 Spark 容器一起使用項目渲染器的函數

在某些應用中,在一個容器中顯示數據項有不同的類型。或者在某些場景中,數據項的每一種類型需要有自己相應的項目渲染器。或者你需要將數據項和 Flex 組件混合在一個容器中。為實現這些功能,給數據項和 Flex 組件定義不同的項目渲染器。

你可以使用項目渲染器函數來測試每個數據項來決定使用哪一個渲染器。 DataGroup.itemRendererFunction 和 skinnableDataContainer.itemRendererFunction 方法使用下面的格式:

function itemRendererFunction(item:Object):ClassFactory

item 表示為一個數據項,返回的值是項目渲染器。如果 item 是 Flex 組件的子類,返回 DefaultComplexItemRenderer 來顯示組容器中的子類。也可以返回 null ,表示不需要渲染器來顯示子類。

下面的示例定義了項目渲染器方法:當參數為一個對象返回了一個項目渲染器,參數為字符串則返回另一個渲染器。

<?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>

你也可以在數據項和 Flex 組件在一個容器內時使用項目渲染器方法。 Flex 組件實現 IVisulaElement 接口,因此不需要項目渲染器在屏幕上畫它們。在你的項目渲染器方法中,你可以定義數據項是否需要相應 Flex 組件,如果要,項目渲染器方法返回 DefaultComplexItemRenderer ,代碼如下:

<?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 項目渲染器的處理順序

DataGroup 和 SkinnableDataContainer 容器使用下面的規則來決定項目渲染器作為它的構成部件:

1.         如果 itemRendererFunction 屬性被定義,調用此方法來獲得項目渲染器。如果沒有定義則使用規則 2.

2.         如果 itemRenderer 屬性被定義,使用指定的項目渲染器來顯示該項。

3.         如果項目實現了 mx.core.IVisualElement 且它是 flash.display.DisplayObject 類型,則直接使用它。

4.         如果沒有發現項目渲染器則拋出實時錯誤。

給 Spark 容器定義內置的項目渲染器

上面所有的項目渲染器示例都定義在 MXML 文件中,這使得它具有高度的可重用性。可以容易的在多個容器中引用它。

你也可以在一個組件中定義一個內置的項目渲染器。使用內置定義可以使得所有的代碼被封裝在一個單獨的文件中。可以,它會降低重用性。

下面的示例展示瞭如何和 SkinnableDataContainer 容器一起使用內置項目渲染器:

<?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>

注意你定義的內置項目渲染器使用的是 DataGroup 容器的 itemRenderer 屬性。 itemRenderer 屬性內的第一個子標籤總是 <fx:Component> 。在 <fx:Component> 內部的代碼和MySimpleItemRenderer.mxml 文件中的內容一樣。

在內置組件中可以使用的項目

內置項目渲染器只有一個規定。你不可以建立一個空的 <fx:Component></fx:Component> 標籤對。例如,你可以將效果、樣式和渲染邏輯一起定義在內置渲染器中。

你在內置項目渲染器中可以包含下列項目:

       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

使用組件標籤

<fx:Component> 標籤在MXML 文件中定義了一個新的作用範圍,項目渲染器本身的作用範圍通過使用<fx:Component></fx:Component> 標籤對來加以界定。如果要訪問作用範圍外部的元素需要在元素名前加一個outerDocument 的前綴。

例如:你在主應用範圍內定義了一個變量叫localVar 。你在渲染器內部定義了一個相同名字的變量。從渲染器內部訪問外部的localVar 使用outerDocument 前綴,請看下面的示例的展示:

<?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>

建立可重用的內置項目渲染器

不是在組件的內部定義一個內置項目渲染器,你可以定義一個在整個項目中可重用的項目渲染器。

為了建立一個可重用的內置的項目渲染器,需要指定 <fx:Component> 的className 屬性,通過給這個類命名,你定義了一個方法來引用這個項目渲染器和項目渲染器的子元素。

下面的示例展示了使用<fx:Component> 標籤來定義內置項目渲染器,並在兩個容器內進行引用:

<?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">
            <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="{inlineRenderer}">
        <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="{inlineRenderer}">
        <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>

在這個示例中,通過數據綁定為 itemRenderer 的屬性值,來指定兩個容器的渲染器。

建立一個可循環使用的項目渲染器

當可視化佈局關閉時, DataGroup 和 SkinnableDataContainer 容器為每一個子元素建立一個實例。當可視化佈局打開時,容器只為當前顯示的可視化子元素只建立必要的項目渲染器。可視化佈局大大減少了使用 DataGroup 和 SkinnableDataContainer 容器過高的需求。

打開可視化佈局時,一個子元素移動到容器的可視範圍之外,它的項目被重複利用。首先,這個項目渲染器的 data 屬性被設置為空。當這個項目渲染器被重新利用,它的 data 屬性被設置為表示新數據的數據項。因此,如果循環使用的項目渲染器執行任何基於數據 data 屬性的操作,它必須首先檢查它的屬性是否為空。

當項目渲染器被重新分配, Flex 首先調用項目渲染器擁有者的 updateRenderer ()方法。這個方法必須設置 owner 和 label 屬性。 SkinnableDataContainer 的子類可以使用updateRenderer ()方法來設置額外的屬性。

因為容器會重新使用項目渲染器,確保你要完全定義它的狀態。例如,你在一個項目渲染器中使用了 CheckBox 控件用來顯示 true 或者 false 值,此值來自於當前 data 屬性。通常會犯得一個錯誤是 CheckBox 控件總是在它的缺省狀態 à unchecked ,它只會檢查 data 屬性的 true 值。

可是, CheckBox 是會被回收的並且它有記住先前的狀態。因此,檢查 data 屬性 false 值,如果它是 checked 狀態,顯式 uncheck 控件,如下面的示例所示:

<?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>

使用 ItemRenderer 的 dataChange 事件來探測 data 屬性的更改,此事件在 data 屬性改變時拋出。同樣,你也可以覆蓋 data 屬性來完成此功能。

覆蓋 ItemRenderer.data 屬性本身完成此功能的示例如下所示:

<?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>

定義一個典型項來確定項目渲染器的大小

當和 DataGroup 和 SkinnableDataContainer 容器一起使用可視化佈局,你能夠傳遞給容器一個數據項,該數據項定義了一個典型的數據項。容器接着使用這個典型的數據項,將其和項目渲染器聯繫起來並決定子元素的缺省大小。通過定義典型數據項,容器在繪製屏幕時不需要確定每一個子元素的大小。

使用容器的 typicalItem 屬性示例如下所示:

<?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>

在這個示例中,你定義了一個 typicalObj 對象。該對象表明了 firstName 和 lastName 的長度。然後傳遞給容器的 typicalItem 屬性。容器使用這個數據項聯繫到項目渲染器,並確定了子元素的大小。