(九)对List和DataGroup使用itemRenderer

数据集
      包含一组数据元素的对象就叫做数据集DataSet
      如:Array、XMLList、ArrayCollection、XMLListCollection
如何显示一个数据集?
   通过labelField指定列表应该显示数据集中哪个属性(局限:只能显示文本)
   如果要显示格式化的数据,或者拼接多个属性,则需要使用LabelFunction
如何操作(增删改查)一个数据集?
   IViewCursor
如何循环一个数据集?
   for循环  for each循环
-----------------------------------------------
List与DataProvider组件
List类与DataGroup类相似,都有一个可以用来设置其数据集的dataProvider
并基于itemRenderer来呈现数据集中的每一项数据!!!
注意:List还有另一个功能,可以管理用户选择的数据项,并可以获取到哪些项被选中(基于这些选中项dosomething)

在List中使用labelFunction属性
       labelFunction指定一个函数,该函数会返回一个String
即:通过该函数实现如何显示List中的每一项


在DataGroup中应用itemRenderer
    系统提供了DefaultItemRenderer,将使用Label组件呈现每个数据项
    创建自定义的itemRenderer
创建itemRenderer时,新类可以实现IDataRenderer接口,也可以继承某个实现了该接口的类
IDataRenderer接口指定了实现它的类必须有实现针对data属性的get和set函数(data通常为Object类型)
itemRenderer的原理:
针对dataProvider中的每一个数据项都创建一个呈现器实例,然后取得相应数据项的数据放到data中


应用程序中复写data的set方法,然后将传入的value赋值给我们自己创建的那个引用,这样就获取到

需要的数据了!

虚拟化与List
    虚拟化:只创建对用户可见的元素的对象。离开用户可见范围的对象将被回收,然后将原有空间设置为显示新入屏

幕的元素。(好处:只创建用户可见的,不可见的马上回收,节省资源消耗)
    如:DataGroup中包含1000个商品,每次显示10个,那么应用程序每次就只创建对用户可见的那10个商品实例
使用方法:
    <s:layout>下的布局对象中设置useVirtalLayout="true"
对于List而言,虚拟化是默认开启的!
而且List列表还支持选择功能:
    列表项用户呈现一些项,用户选择,列表围绕被选择项提供了很多操作
    如:属性、方法、事件
    selectedIndex、selectedItem属性可以指定或者取得当前选中的项
--------------------------------------------------------------------创建一个呈现器,在应用程序顶部的控制条中通过呈现器来显示不同商品类别
根据选择的类别显示商品(实现筛选功能)

1.使用List存放控制条中显示的商品种类
2.使用itemRenderer属性指定一个自定义的项目呈现器进行自定义的格式显示
3.因为List还支持事件、属性等,所以可以对列表中选中商品的变化作出响应

主程序:FlexGrocery.mxml
<?xml version="1.0" encoding="utf-8"?>
<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"
			   creationComplete="handleCreationComplete(event)" xmlns:views="views.*" xmlns:services="services.*">

	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
		<!-- 将HTTPService获取数据的功能放到两个ActionScript类中进行处理,此处引入即可 -->
		<!-- 提供商品类别服务的组件(不可见组件)-->
		<services:CategoryService id="categoryService"/>
		<!-- 提供具体各种商品服务的组件(不可见组件)-->
		<services:ProductService id="productService"/>
	</fx:Declarations>

	<fx:Script>
		<![CDATA[
			import mx.events.FlexEvent;
			
			import spark.events.IndexChangeEvent;
			//当系统组件构建完成后,会调用到此方法,在这里向远端发起请求,获取数据
			//当数据获取成功后,事件监听器会调用指定的方法处理数据
			private function handleCreationComplete(event:FlexEvent):void {
				categoryService.send();
				productService.send();
			}
			
			//查看当前购物车中的商品
			private function handleViewCartClick( event:MouseEvent ):void {
				bodyGroup.currentState="cartView";//切换到bodyGroup下的cartView状态
			}
			
			//响应列表的变化,对change事件进行处理
			protected function list1_changeHandler(event:IndexChangeEvent):void
			{
				//当控制条中商品的选中状态改变了,会触发change事件,该方法就会得到执行
				//传入当前选中商品的catID,然后products集合会根据此id寻找对应的项,并只呈现匹配的哪些项
				productService.filterCollection(event.target.selectedItem.categoryID);
			}
			
		]]>
	</fx:Script>
	
	<!-- 控制条布局 -->
	<s:controlBarLayout>
		<s:BasicLayout/>
	</s:controlBarLayout>
	
	<!-- 控制条 -->
	<s:controlBarContent>
		<s:Button y="10" label="Checkout" id="btnCheckout" right="10"/>
		<s:Button y="10" label="View Cart" id="btnCartView" right="90" click="handleViewCartClick( event )"/>
		<s:Button label="Flex Grocer" x="5" y="5"/>
		<!-- 从categoryService中获取商品种类信息 ,使用指定的项目呈现器NavigationItem显示内容-->
		<s:List left="200" height="52" 
				dataProvider="{categoryService.categories}"
				itemRenderer="components.NavigationItem"
				change="list1_changeHandler(event)">
			<s:layout>
				<s:HorizontalLayout/>
			</s:layout>
		</s:List>	</s:controlBarContent>
	
	<!-- 实例化商品组件(该组件被单独抽取出来,在主应用程序中实例化) -->
	<!-- 从productService中获取商品 -->
	<views:ShoppingView id="bodyGroup" width="100%" height="100%" groceryInventory="{productService.products}"/>	
	
	<!-- 版权说明 -->
	<s:Label text="(c) 2009, FlexGrocer" right="10" bottom="10"/>
</s:Application>



项目呈现器NavigationItem.mxml
<?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">
	<s:layout>
		<s:VerticalLayout horizontalAlign="center"/>
	</s:layout>
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
	</fx:Declarations>
	<!-- flex会将针对dataProvider中每项创建对应的呈现器实例,然后将取得的相应数据放到data中-->
	<s:Image source="assets/nav_{data.name.toLowerCase()}.jpg"
			 height="31" width="93"/>
	<s:Label text="{data.name}"/>
</s:ItemRenderer>



ProductService.as
对集合中的商品进行过滤,只显示被选择的那类商品
package services
{
	import mx.collections.ArrayCollection;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.mxml.HTTPService;
	
	import valueObjects.Product;

	/**
	 * 该类用于获取所有的商品
	 * 对外提供products(products为ArrayCollection,存放着所有商品) 
	 * @author lenovo
	 * 
	 */	
	public class ProductService extends HTTPService
	{
		[Bindable]
		public var products:ArrayCollection;//获取远程数据,使用e4x找出product节点,转换为对象,放入Array,最后将Array放入ArrayCollection
		
		
		public function ProductService(rootURL:String=null, destination:String=null)
		{
			super(rootURL, destination);
			this.resultFormat = "e4x";//指定返回xml格式的数据以便使用e4x表达式对xml进行操作
			this.url = "http://www.flexgrocer.com/categorizedProducts.xml";//数据源
			this.addEventListener(ResultEvent.RESULT,handleProductResult);//事件监听器,并指定事件处理函数
		}
		
		private function handleProductResult( event:ResultEvent ):void {
			var productArray:Array = new Array();
			var resultData:XMLList = event.result..product;//e4x筛选子节点
			for each (var p:XML in resultData) {			
				var product:Product = Product.buildProductFromAttributes( p );//将每个子节点创建对应的product对象
				productArray.push( product );//添加到数组中
			}
			products = new ArrayCollection( productArray );//将整个数组放入ArrayCollection中,为数组提供代理
			
			//为products集合(ArrayCollection)指定一个筛选函数
			products.filterFunction = filterForCategory;
			products.refresh();//刷新集合
		}
		
		//默认选择index=1的商品
		private var selectedCategory:Number=1;
		
		//products集合的过滤函数
		public function filterForCategory(item:Product) :Boolean {
			return item.catID == selectedCategory;//将集合中的每项的catID与selectedCategory进行比较,结果为true的那项将被呈现
		}
		
		//当选择其它商品时发生change事件,会将其catID传入到此方法,然后赋值给selectedCategory
		//调用集合的refresh方法,重新对集合进行过滤,过滤的时候使用的selectedCategory就是刚才传入的catID
		public function filterCollection(id:Number):void {
			selectedCategory = id;
			products.refresh();
		}
	}
}


====================================================================
对bodyGroup中的商品进行呈现
1.使用DataGroup
2.使用DataRenderer

ShoppingView.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx" width="0" height="0" xmlns:components="components.*">
	<s:layout>
		<s:HorizontalLayout/>
	</s:layout>
	<s:states>
		<s:State name="State1"/>
		<s:State name="cartView"/>
	</s:states>
	

	<fx:Script>
		<![CDATA[
			import cart.ShoppingCart;
			import cart.ShoppingCartItem;
			
			import components.ProductItem;
			
			import mx.collections.ArrayCollection;
			
			import valueObjects.Product;
			[Bindable]
			public var shoppingCart:ShoppingCart = new ShoppingCart();//创建一个购物车,分别传入不同的商品对象中,而不是在每种商品中都new一个购物车!
			[Bindable]
			public var groceryInventory:ArrayCollection;//用于存放HTTPService返回的各种商品信息
			
			//查看当前购物车中的商品
			private function handleViewCartClick( event:MouseEvent ):void {
				this.currentState="cartView";
			}
			
			//该方法返回一个字符串,用来作为数据集的呈现方式,由labelFunction函数指定
			//当List中使用labelFunction时,会自动以正确的方式从dataProvider中获取数据并传递到该方法中
			//返回的字符串将作为被呈现的内容
			private function renderProductName(item:ShoppingCartItem):String {
				var product:Product = item.product;
				return "("+item.quantity+")" + product.prodName + " $" + item.subtotal;
			}
		]]>
	</fx:Script>
	
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
	</fx:Declarations>
	
	<!-- 必须为组件指定在界面中占据的空间大小 否则不可见-->
	<s:DataGroup width="100%" height="100%" 
				 width.cartView="0" height.cartView="0" visible.cartView="false"
				 dataProvider="{groceryInventory}"
				 itemRenderer="components.ProductItem">
		<!-- dataProvider属性指定数据来源,itemRenderer属性负责数据呈现 -->
		<!-- 将ProductItem改为了一个DataRenderer-->
		
		<!-- 为DataGroup指定布局对象,否则展现出来的视图都重叠在一起了 -->
		<s:layout>
			<s:VerticalLayout/>
		</s:layout>
	</s:DataGroup>
	
	<!-- 购物车组件 -->
	<s:VGroup id="cartGroup" height="100%"  width.cartView="100%">
		<s:List id="cartList"
				dataProvider="{shoppingCart.items}" includeIn="State1"
				labelFunction="renderProductName"/>			
		<s:Label text="Your Cart Total: $"/>
		<s:Button label="View Cart" click="handleViewCartClick( event )" includeIn="State1"/>
		<mx:DataGrid includeIn="cartView" id="dgCart" width="100%">
			<mx:columns>
				<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
				<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
				<mx:DataGridColumn headerText="Column 3" dataField="col3"/>
			</mx:columns>
		</mx:DataGrid>
		<s:Button includeIn="cartView" label="Continue Shopping" click="this.currentState=''"/>
	</s:VGroup>
</s:Group>

ProductItem.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:DataRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx" 
		 width="100%">

	<s:states>
		<s:State name="State1"/>
		<s:State name="expanded"/>
	</s:states>
	
	<fx:Script>
		<![CDATA[
			import cart.ShoppingCart;
			import cart.ShoppingCartItem;
			
			import valueObjects.Product;
			[Bindable]
			public var product:Product;//由flex在为data赋值的时候,将value赋值给product
			
			public var shoppingCart:ShoppingCart;//购物车从哪里传入呢?
			
			//添加某类商品到购物车,一次添加1个
			private function addToCart(product:Product):void {
				var sci:ShoppingCartItem = new ShoppingCartItem( product );
				shoppingCart.addItem( sci );
			}
			
			//从购物车中删除该类商品,一次性全部删除
			private function removeFromCart( product:Product ):void {
				var sci:ShoppingCartItem = new ShoppingCartItem( product );
				shoppingCart.removeItem( sci );
			}
			
			//当指定了dataProvider之后,flex会针对数据集中每个数据项创建一个呈现器实例
			//然后将取得的数据放到data中保存
			//这里覆盖data的set方法,利用上述原理,在赋值时直接将数据赋值到product对象中,而不是赋值给data
			public override function set data(value:Object) :void {
				this.product = value as Product; //注意进行类型转换
			}
		]]>
	</fx:Script>
	
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
	</fx:Declarations>
	
	<!-- 商品 -->
	<s:VGroup  id="products">
		<s:Label text="{product.prodName}" id="prodName"/>
		<mx:Image source="assets/{product.imageName}" scaleContent="true" 
				  mouseOver="this.currentState='expanded'"
				  mouseOut="this.currentState='State1'"/>
		<s:Label text="${product.listPrice}" id="price"/>
		<s:Button label="AddToCart" id="add"
				  click="addToCart(product )"/>
		<s:Button label="Remove From Cart" id="remove"
				  click="removeFromCart(product )"/>			
	</s:VGroup>
	
	<!-- 商品详细信息 -->
	<s:VGroup includeIn="expanded" x="200" width="100%">
		<s:RichText text="{product.description}"
					width="50%"/>
		<s:Label text="Certified Organic"
				 visible="{product.isOrganic}"/>
		<s:Label text="Low Fat"
				 visible="{product.isLowFat}"/>
	</s:VGroup>
</s:DataRenderer>

你可能感兴趣的:(itemRenderer)