理解 Flex itemRenderer - 第 2 部分: 外部渲染器

原文地址:http://www.adobe.com/cn/devnet/flex/articles/itemrenderers_pt2.html

 

本系列的第 1 部分中, 我向您展示了如何创建内联 itemRenderer-这种 itemRenderer 的 MXML 标记和 ActionScript 代码与使用该 itemRenderer 的列表位于同一文件中。代码与文件中的其余代码内联。

您应该还记得我说过, 应该将内联 itemRenderer 视作单独的类。事实上, Flex 编译器提取这些内联代码并为您创建类。内联 itemRenderer 的优势在于代码与列表位于同一位置, 但是如果 itemRenderer 变得复杂时, 这又变成了劣势。本文中我将向您展示如何自己创建类。

将 itemRenderer 提取到一个外部文件有几个优势:

  • itemRenderer 可轻松用于多个列表中
  • 代码更容易维护
  • 可以使用 Flex Builder 的“设计”视图草拟出最初的 itemRenderer

本系列包含以下文章:

  • 第 1 部分: 内联渲染器
  • 第 2 部分: 外部渲染器
  • 第 3 部分: 通信
  • 第 4 部分: 状态和过渡
  • 第 5 部分: 效率

要求

为了充分利用本文, 您需要以下软件和文件:

Flex Builder 3

必要条件:

要从本文中受益, 您最好熟悉 Flex Builder 和 ActionScript 3.0。

ActionScript itemRenderer

现在, 您将编写另一个 itemRenderer, 这次使用 ActionScript 类。在上一篇文章中, 有一个 TileList 包含这个内联 itemRenderer:

	<mx:itemRenderer>
		<mx:Component>
			<mx:HBox verticalAlign="top">
				<mx:Image source="{data.image}" />
				<mx:VBox height="115" verticalAlign="top" verticalGap="0">
					<mx:Text text="{data.title}" fontWeight="bold" width="100%"/>

					<mx:Spacer height="20" />
					<mx:Label text="{data.author}" />
					<mx:Label text="Available {data.date}" />
					<mx:Spacer height="100%" />
					<mx:HBox width="100%" horizontalAlign="right">
						<mx:Button label="Buy" fillColors="[0x99ff99,0x99ff99]">

							<mx:click>
							<!--[CDATA[
								var e:BuyBookEvent = new BuyBookEvent();
								e.bookData = data;
								dispatchEvent(e);
							]]-->
							</mx:click>
						</mx:Button>

					</mx:HBox>
				</mx:VBox>
			</mx:HBox>
		</mx:Component>
	</mx:itemRenderer> 

您将把它转变为一个 ActionScript 外部 itemRenderer。您需要执行以下步骤:

  1. 新建一个 ActionScript 类。将它命名为 BookTileRenderer.as 并使它扩展 HBox, 就像内联 itemRenderer 那样。

    package
    {
    	import flash.events.MouseEvent;
    	
    	import mx.containers.HBox;
    	import mx.containers.VBox;
    	import mx.controls.Button;
    	import mx.controls.Image;
    	import mx.controls.Label;
    	import mx.controls.Spacer;
    	import mx.controls.Text;
    	
    	public class BookTileRenderer extends HBox
    	{
    		public function BookTileRenderer()
    		{
    			super();
    		}
    		
    	}
    } 
  2. 创建成员变量, 用于存放子组件的引用。

    		private var coverImage:Image;
    		private var titleText:Text;
    		private var spacer1:Spacer;
    		private var authorLabel:Label;
    		private var pubdateLabel:Label;
    		private var spacer2:Spacer;
    		private var buyButton:Button; 
  3. 覆盖 createChildren() 函数以创建子组件, 并将它们添加到 HBox。

    		override protected function createChildren():void
    		{
    			coverImage = new Image();
    			addChild(coverImage);
    			
    			var innerBox:VBox = new VBox();
    			innerBox.explicitHeight = 115;
    			innerBox.percentWidth = 100;
    			innerBox.setStyle("verticalAlign","top");
    			innerBox.setStyle("verticalGap", 0);
    			addChild(innerBox);
    			
    				titleText = new Text();
    				titleText.setStyle("fontWeight","bold");
    				titleText.percentWidth = 100;
    				innerBox.addChild(titleText);
    			
    				spacer1 = new Spacer();
    				spacer1.explicitHeight = 20;
    				innerBox.addChild(spacer1);
    			
    				authorLabel = new Label();
    				innerBox.addChild(authorLabel);
    			
    				pubdateLabel = new Label();
    				innerBox.addChild(pubdateLabel);
    			
    				spacer2 = new Spacer();
    				spacer2.percentHeight = 100;
    				innerBox.addChild(spacer2);
    			
    				var buttonBox:HBox = new HBox();
    				buttonBox.percentWidth = 100;
    				buttonBox.setStyle("horizontalAlign","right");
    				innerBox.addChild(buttonBox);
    			
    					buyButton = new Button();
    					buyButton.label = "Buy";
    					buyButton.setStyle("fillColors",[0x99ff99,0x99ff99]);
    					buyButton.addEventListener(MouseEvent.CLICK, handleBuyClick);
    					buttonBox.addChild(buyButton);
    		} 

    我准备通过这一代码显示父子关系。同时, 确保在 Buy 按钮中包含一个事件侦听器。

  4. 覆盖 commitProperties() 函数, 并从数据设置用户界面控制。

    		override protected function commitProperties():void
    		{
    			super.commitProperties();
    			
    			coverImage.source = data.image;
    			titleText.text = data.title;
    			authorLabel.text = data.author;
    			pubdateLabel.text = data.date;
    		} 
  5. 为 Buy 按钮添加单击事件处理函数。

    		private function handleBuyClick( event:MouseEvent ) : void
    		{
    			var e:BuyBookEvent = new BuyBookEvent();
    			e.bookData = data;
    			dispatchEvent(e);
    		} 
  6. 将主应用程序中的 TileList 修改为使用 itemRenderer ActionScript 类。只需删除 inlineItemRenderer 并将它替换为标记中的 itemRenderer 属性。

    <mx:TileList id="mylist" x="29" y="542" width="694" itemRenderer="BookTileRenderer" 
           dataProvider="{testData.book}" height="232" columnWidth="275" rowHeight="135" > 

如果要使用一个现有容器类, 如 HBox, 我不会使用 ActionScript 这样做。您会发现它比使用 MXML 文件复杂, 并且老实说, 性能方面几乎没有任何优势。

可重用的 itemRenderer

以下是一个 itemRenderer 示例, 它使用 CurrencyFormatter 显示一个数值。我称之为 PriceFormatter:

<?xml version="1.0" encoding="utf-8"?>
<mx:Text xmlns:mx="http://www.adobe.com/2006/mxml">

	<mx:Script>
		<!--[CDATA[
			import mx.controls.dataGridClasses.DataGridListData;
			
			[Bindable] private var formattedValue:String;
			
			override public function set data(value:Object):void
			{
				super.data = value;
				
				formattedValue = cfmt.format( Number(data[(listData as DataGridListData).dataField]) );

			}
		]]-->
	</mx:Script>
	
	<mx:CurrencyFormatter precision="2" id="cfmt" />
	
	<mx:text>{formattedValue}</mx:text>
	
</mx:Text> 

这个 itemRenderer 的关键部分以红色标出, 设置可绑定变量 formattedValue。首先, 您会发现 <mx:CurrentFormatter> 使用 id cfmt 定义为 MXML 标记 (如果您愿意, 也可以使用 ActionScript 这样做)。在上例中, formattedValue 设置为 CurrentFormatter 的 format() 函数的调用结果。

此函数将 Number 作为其参数类型, 所以值被转换为 Number-这是因为列表的 dataProvider 是 XML 并且 XML 中的所有内容是文本; 如果为数据使用 Object 并且您有实际数值, 执行 Number 转变将是无害的。

如您所知, 数据是存放 itemRenderer 所显示项目的属性。使用 [ ] 记号是访问数据项目字段的另一种方法。例如, data['price'] 是价格列。但是为了使这个 itemRenderer 可重用, 您不能为特定字段编码, 所以需要一种更普通的方法。

此时, listData 登台亮相。实施 IDropInListItemRenderer 接口的所有 Flex 组件都有一个 listData 属性。

注意: Text、Label、Button、CheckBox 等大多数控制都实施 IDropInListItemRenderer。HBox、Canvas 等大多数容器实施此接口。如果要在扩展 Container 的 itemRenderer 中使用 listData, 您必须自己实施 IDropInListItemRenderer; 我将在下一篇文章中讨论这个问题。

除了其他内容, 提供给 itemRenderer 的 listData 还包含 rowIndex 和控制, 该控制拥有 itemRenderer-DataGrid、List 或 TileList。将 itemRenderer 用于 DataGrid 时, listData 实际上是一个 DataGridListData 对象-它包含 columnIndex 以及与 DataGridColumn 关联的 dataField。以下是上述语句的明细, 从内部开始:

  • listData as DataGridListData-它将 listData 转换为 DataGridListData 对象, 使您能访问它的 dataField
  • .dataField-该字段用于渲染的列。它使这个 itemRenderer 变得一般。可以将这个 itemRenderer 用于多个列。在本例中, dataField 是“price”。
  • data[ ... ]-它访问项目中特定字段的数据。在本例中, 它是价格列。
  • Number( ... )-它将值转换为 Number, 因为 format() 函数需要一个 Number 参数。
  • cfmt.format( ... )-它将值格式化为货币。

后续工作

实施 itemRenderer 时, 可使用您喜欢的任何语言。一些人只适用 ActionScript, 当然如果您具有 Flex 和 ActionScript 方面的经验, 这很棒。MXML 也可以快速创建出简单的 itemRenderer。

在第 3 部分 (即将推出) 中, 我将进一步讨论 itemRenderer 与应用程序其余部分之间的通信。

关于作者

Peter Ent 是 Adobe 的一名计算机科学家,目前正在进行 Genesis 项目。在此之前,Peter 担任过 Adobe 客户关怀的 Flex 支持工程师以及技术客户经理。加入 Adobe 之前,Peter 曾在 State Street and Fidelity Investments 的金融服务行业工作。他还在两家新成立的公司构建过用于成像和分子建模的软件应用程序。Peter 获得美国雪城大学的计算机科学理科学士学位。访问 Peter 的博客*

你可能感兴趣的:(理解 Flex itemRenderer - 第 2 部分: 外部渲染器)