自定义 Spark item 的渲染器
在 DAtaGroup , SkinnableDataContainer 或它们的子类中定义自己的项目渲染器可以控制数据项的显示外观,数据项的外观包括字体、背景色、边界和其他的可视方面。项目渲染器也可以在和用户进行交互的时候指定要显示的外观。例如,用户鼠标移动到数据项上时显示一种外观,当用户点击时显示另一种外观。Spark 项目渲染器的基类 ItemRenderer 已经内置支持了所有用户要进行交互。缺省项目渲染器 DefaultItemRenderer 和 DefaultComplexItemRenderer 支持这些用户的交互操作。在你自定义的项目渲染器中,你可以选择依赖 ItemRenderer 类支持的缺省交互支持还是实现你自己的交互。许多 Spark 组件既支持皮肤也支持项目渲染器。当项目渲染器定义了数据项的外观,皮肤定义了组件完整的可视化外观。皮肤可以包含边界、滚动条和组件外观的其他方面。详细的信息参考 Spark Skinning 。
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 属性。容器使用这个数据项联系到项目渲染器,并确定了子元素的大小。
更多的关于 typeicalLayoutElement 属性的信息参阅 设置布局中的行高和列宽 。