(十四)Flex4_导航

Flex中实现导航有两种方式可以实现
1.使用状态,在不同事件发生时切换到指定的状态,不同的状态对应不同的视图界面
2.使用导航容器
--------------------------------------------------------------------
导航:实现多页视图的切换显示

1.实现导航基础的ViewStack类
2.NavigationContent类,该类支持在ViewStack中使用基于Spark的容器
3.实现导航时使用ViewStack类的selectedIndex和selectedChild属性



导航容器
重要概念:
    容器:ViewStack
    组件:NavigationContent  (Spark元素)
说明:
任何实现了INavigationContent接口的类都可以作为ViewStack的子元素。
在spark中,NavigationContent实现了INavigationContent并且继承了Sprak Group类
导航容器每次只显示一个子元素,ViewStack通过切换其子元素的可见性实现子元素的呈现

如何切换元素呢?
    通过selectedChild和selectedIndex属性控制元素在导航容器中的可见性
[selectedIndex:ViewStack索引从0开始,第一个子元素的索引为0]
[selectedChilde:通过引用子元素的id值,从而指定ViewStack显示哪个元素]
----------------------------------------------------------------
1.主程序设置状态:
	<s:states>
		<s:State name="shoppingView"/>
		<s:State name="checkoutView"/>
	</s:states>

一个为购物状态(对应购物组件),一个为结账状态(对应结账组件),通过不同的状态切换到不同的界面。
购物车实例在主程序中创建,然后通过组件的属性绑定到它们当中,实现购物与结账时购物车的共享。
界面中有各种按钮,点击之后发生click事件,在对应的事件处理函数中设currentState即可实现状态的切换!
用户选购商品结账时,会发生自定义事件placeOrder,在主程序中监听并处理:弹出一个对话框,显示购物简要信息,最后清空购物车,让程序的各个状态回到初始状态!
FlexGrocer.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.*" xmlns:cart="cart.*">
	
	<!-- 购物视图、结账视图-->
	<s:states>
		<s:State name="shoppingView"/>
		<s:State name="checkoutView"/>
	</s:states>
	
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
		<!-- 将HTTPService获取数据的功能放到两个ActionScript类中进行处理,此处引入即可 -->
		<!-- 提供商品类别服务的组件(不可见组件)-->
		<services:CategoryService id="categoryService"/>
		<!-- 提供具体各种商品服务的组件(不可见组件)-->
		<services:ProductService id="productService"/>
		
		<!-- 创建购物车实例,将同一个对象传入到shoppingView和checkoutView两个状态下-->
		<cart:ShoppingCart id="shoppingCart"/>
	</fx:Declarations>

	<fx:Script>
		<![CDATA[
			import events.OrderEvent;
			
			import mx.controls.Alert;
			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);
			}
			
			protected function btnCheckout_clickHandler(event:MouseEvent):void
			{
				// 转到结账视图
				this.currentState = "checkoutView";
			}
			
			protected function FlexGrocer_clickHandler(event:MouseEvent):void
			{
				// 转到购物视图
				this.currentState = "shoppingView";
			}
			
			// 主应用程序的checkoutView组件派发placeOrder自定义事件之后,表示需要完成结账
			protected function checkout_placeOrderHandler(event:OrderEvent):void
			{
				//当用户结账时,弹出提示框描述相关信息
				Alert.show("Place an order for " +event.order.billingName + 
					" with a total of " + shoppingCart.total,"Order Placed");
				//清空购物车
				shoppingCart = new ShoppingCart();
				
				//当前状态切换到购物视图状态
				this.currentState = "shoppingView";
				
				//防止ShoppingView组件处于cartView状态,将其切换回State1状态
				bodyGroup.currentState = "State1";
			}
			
		]]>
	</fx:Script>
	
	<!-- 控制条布局 -->
	<s:controlBarLayout>
		<s:BasicLayout/>
	</s:controlBarLayout>
	
	<!-- 控制条 -->
	<s:controlBarContent>
		<s:Button y="10" label="Checkout" id="btnCheckout" right="10"
				  click="btnCheckout_clickHandler(event)"/>
		<s:Button y="10" label="View Cart" id="btnCartView" right="90" 
				  click="handleViewCartClick( event )"/>
		<s:Button label="Flex Grocer" x="5" y="5"
				  click="FlexGrocer_clickHandler(event)"/>
		
		<!-- 从categoryService中获取商品种类信息 ,使用指定的项目呈现器NavigationItem显示内容-->
		<s:List left="200" height="52" 
				dataProvider="{categoryService.categories}"
				itemRenderer="components.NavigationItem"
				change="list1_changeHandler(event)"
				includeIn="shoppingView">
			<s:layout>
				<s:HorizontalLayout/>
			</s:layout>
		</s:List>
	</s:controlBarContent>
	
	<!-- 实例化商品组件(该组件被单独抽取出来,在主应用程序中实例化) -->
	<!-- 从productService中获取商品 -->
	<views:ShoppingView id="bodyGroup" width="100%" height="100%" 
						groceryInventory="{productService.products}"
						includeIn="shoppingView"
						shoppingCart="{shoppingCart}"/>	
	
	<!-- 结账视图-->
	<views:CheckOutView x="0" y="0" width="100%" height="100%"
						includeIn="checkoutView"
						shoppingCart="{shoppingCart}"
						placeOrder="checkout_placeOrderHandler(event)"/>
	
	<!-- 版权说明 -->
	<s:Label text="(c) 2009, FlexGrocer" right="10" bottom="10"/>
</s:Application>


CheckOutView.mxml
该组件将在用户点击checkout时呈现
定义了1个ViewStack和3个NavigationContent,通过控制selectIndex实现导航
第1个导航页面为用户基本信息的录入
第2个导航页面为银行卡信息的录入
第3个导航为结账页面,左边显示用户前面录入的信息,右边显示购物车中的购物详情,用户可以选择结账或者重新编辑信息
<?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" xmlns:valueObjects="valueObjects.*" xmlns:checkout="views.views.checkout.*">
	
	<s:layout>
		<s:VerticalLayout/>
	</s:layout>
	
	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
		<!-- 创建OrderInfo数据模型对象-->
		<valueObjects:OrderInfo id="orderInfo"/>
	</fx:Declarations>
	
	<!-- 声明自定义OrderEvent事件(当completeOrder的时候会发生此事件)-->
	<fx:Metadata>
		[Event(name="placeOrder", type="events.OrderEvent")]
	</fx:Metadata>
	
	<fx:Script>
		<![CDATA[
			import cart.ShoppingCart;
			
			import events.OrderEvent;
			
			[Bindable]
			public var shoppingCart:ShoppingCart;
			
			//继续到下一个页面
			protected function proceedHandler(event:Event):void
			{
				vs.selectedIndex += 1;
				
			}
			//返回编辑信息,即回到初始页面
			protected function editInformationHandler(event:Event):void
			{
				vs.selectedIndex = 0;
			}
			//完成订单,结账
			protected function completeOrderHandler(event:Event):void
			{
				// 为下一个订单重置导航
				vs.selectedIndex = 0;
				
				// 在自定义事件对象中设置orderInfo对象并派发
				this.dispatchEvent(new OrderEvent('placeOrder',orderInfo));
				
				// 清除订单对象,为下一次做准备
				orderInfo = new OrderInfo();
			}
			
		]]>
	</fx:Script>
	
	
	<!-- 利用ViewStack结合NavigationContent实现导航-->
	<mx:ViewStack id="vs" width="100%" height="100%">
		<!-- page 1 可以进入下一页-->
		<checkout:CustomerInfo orderInfo="{orderInfo}" 
							   width="100%" height="100%"
							   proceed="proceedHandler(event)"/>
		<!-- page 2 可以进入下一页-->
		<checkout:CreditCardInfo orderInfo="{orderInfo}" 
								 width="100%" height="100%"
								 proceed="proceedHandler(event)"/>
		<!-- page 3 可以返回第一页重新编辑信息,也可以结账完成订单-->
		<checkout:Review orderInfo="{orderInfo}" 
						 width="100%" height="100%"
						 shoppingCart="{shoppingCart}"
						 editInformation="editInformationHandler(event)"
						 completeOrder="completeOrderHandler(event)"/>
	</mx:ViewStack>
</s:Group>


自定义订单事件,当用户点击Complete Order按钮时触发
package events {
	import flash.events.Event;
	
	import valueObjects.OrderInfo;
	
	public class OrderEvent extends Event {
		public var order:OrderInfo;
		
		//通过构造函数初始化自定义事件对象
		//在事件对象中设置订单对象,事件监听器可以从event中取出该订单对象,从而获取到订单的详细信息
		public function OrderEvent(type:String, order:OrderInfo ) {
			this.order = order;
			super(type);
		}
		
		override public function clone():Event {
			return new OrderEvent( type, order );
		}
	}
}


以下是3个导航页面
第一个用户基本信息的录入
用户点击proceed将发生proceed触发click事件,在事件处理函数中派发proceed自定义事件,在父容器中对该事件捕获,在事件处理函数中将ViewStack的selectedIndex加1,导航到第2个页面
<?xml version="1.0" encoding="utf-8"?>
<s:NavigatorContent 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:HorizontalLayout/>
	</s:layout>
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>

	<fx:Metadata>
		[Event(name="proceed", type="flash.events.Event")]
	</fx:Metadata>
	
	<fx:Script>
		<![CDATA[
			import valueObjects.OrderInfo;
			[Bindable]
			public var orderInfo:OrderInfo;
			
			private function handleProceed( event:Event ):void {
				dispatchEvent( new Event( 'proceed' ) );
			}
		]]>
	</fx:Script>
	<s:Label text="Checkout Page 1 of 3"/>
	<mx:Form>
		<mx:FormHeading label="Customer Information"/>
		<mx:FormItem label="Customer Name">
			<!-- "@"符表示将会把输入的数据设置到对象的属性中,传说中的双向数据绑定? -->
			<s:TextInput text="@{orderInfo.billingName}"/>
		</mx:FormItem>
		<mx:FormItem label="Address">
			<s:TextInput text="@{orderInfo.billingAddress}"/>
		</mx:FormItem>
		<mx:FormItem label="City">
			<s:TextInput text="@{orderInfo.billingCity}"/>
		</mx:FormItem>
		<mx:FormItem label="State">
			<s:TextInput text="@{orderInfo.billingState}"/>
		</mx:FormItem>
		<mx:FormItem label="Zip">
			<s:TextInput text="@{orderInfo.billingZip}"/>
		</mx:FormItem>
		<mx:FormItem label="Delivery Date">
			<mx:DateField selectedDate="@{orderInfo.deliveryDate}"/>
		</mx:FormItem>
		<mx:FormItem>
			<s:Button label="Proceed" click="handleProceed( event )"/>
		</mx:FormItem>
	</mx:Form>
</s:NavigatorContent>

第二个用户银行卡信息的录入,用户点击proceed将发生click事件,在事件处理函数中派发proceed自定义事件,在父容器中对该事件捕获,事件处理函数中将ViewStack的selectedIndex加1,导航到第3个页面
<?xml version="1.0" encoding="utf-8"?>
<s:NavigatorContent 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:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>

	<fx:Metadata>
		[Event(name="proceed", type="flash.events.Event")]
	</fx:Metadata>

	<fx:Script>
		<![CDATA[
			import mx.collections.IList;
			
			import spark.events.IndexChangeEvent;
			
			import valueObjects.OrderInfo;
			[Bindable]
			public var orderInfo:OrderInfo;
			
			private function handleProceed( event:Event ):void {
				dispatchEvent( new Event( 'proceed' ) );
			}
		]]>
	</fx:Script>
	<s:Label text="Checkout Page 2 of 3"/>
 
	<mx:Form>
		<mx:FormHeading label="Billing Information"/>
		<mx:FormItem label="Credit Card Type">
			<s:DropDownList selectedItem="@{orderInfo.cardType}" requireSelection="true">
				<s:dataProvider>
					<s:ArrayList>
						<fx:String>American Express</fx:String>
						<fx:String>Diners Club</fx:String>
						<fx:String>Discover</fx:String>
						<fx:String>MasterCard</fx:String>
						<fx:String>Visa</fx:String>
					</s:ArrayList>
				</s:dataProvider>
			</s:DropDownList>
		</mx:FormItem>
		<mx:FormItem label="Card Number">
			<s:TextInput text="@{orderInfo.cardNumber}"/>
		</mx:FormItem>
		<mx:FormItem label="Expiration" direction="horizontal">
			<s:DropDownList selectedItem="@{orderInfo.cardExpirationMonth}" requireSelection="true">
				<s:dataProvider>
					<s:ArrayList>
						<fx:String>January</fx:String>
						<fx:String>February</fx:String>
						<fx:String>March</fx:String>
						<fx:String>April</fx:String>
						<fx:String>May</fx:String>
						<fx:String>June</fx:String>
						<fx:String>July</fx:String>
						<fx:String>August</fx:String>
						<fx:String>September</fx:String>
						<fx:String>October</fx:String>
						<fx:String>November</fx:String>
						<fx:String>December</fx:String>
					</s:ArrayList>
				</s:dataProvider>
			</s:DropDownList>
			<s:DropDownList selectedItem="@{orderInfo.cardExpirationYear}" requireSelection="true">
				<s:dataProvider>
					<s:ArrayList>
						<fx:String>2010</fx:String>
						<fx:String>2011</fx:String>
						<fx:String>2012</fx:String>
						<fx:String>2013</fx:String>
						<fx:String>2014</fx:String>
						<fx:String>2015</fx:String>
					</s:ArrayList>
				</s:dataProvider>
			</s:DropDownList>
		</mx:FormItem>
		<mx:FormItem>
			<s:Button label="Proceed" click="handleProceed( event )"/>
		</mx:FormItem>
	</mx:Form>
	
</s:NavigatorContent>

第三个结账页面,用户点击Edit Information按钮触发click事件,然后在事件处理函数中派发自定义事件:editInformation事件,父容器监听该事件,并在事件处理函数中将ViewStack的selectedIndex置为0;
用户点击Complete Order按钮触发click事件,然后在事件处理函数中派发自定义事件:completeOrder事件,父容器(CheckOutView.mxml)监听该事件,并在事件处理函数中:弹出对话框,提示购物的相关简要信息,然后清空购物车,恢复程序的初始状态等.
<?xml version="1.0" encoding="utf-8"?>
<s:NavigatorContent xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:components="components.*">
	<s:layout>
		<s:VerticalLayout/>
	</s:layout>
	<fx:Declarations>
		<!-- Place non-visual elements (e.g., services, value objects) here -->
	</fx:Declarations>

	<fx:Metadata>
		[Event(name="editInformation", type="flash.events.Event")]
		[Event(name="completeOrder", type="flash.events.Event")]
	</fx:Metadata>

	<fx:Script>
		<![CDATA[
			import cart.ShoppingCart;
			import cart.ShoppingCartItem;
			
			import events.OrderEvent;
			import events.ProductEvent;
			
			import valueObjects.OrderInfo;
			import valueObjects.Product;

			[Bindable]
			public var shoppingCart:ShoppingCart;
			
			[Bindable]
			public var orderInfo:OrderInfo;
			
			private function handleComplete( event:Event ):void {
				dispatchEvent( new Event( 'completeOrder' ) );  
			}
			
			private function handleEdit( event:Event ):void {
				dispatchEvent( new Event( 'editInformation' ) );	
			}

			private function removeProductHandler(event:ProductEvent):void {
				var sci:ShoppingCartItem = new ShoppingCartItem( event.product );
				shoppingCart.removeItem( sci );
			}			

		]]>
	</fx:Script>
	<s:Label text="Checkout Page 3 of 3"/>
	
	<s:HGroup width="100%" height="90%">
		<!-- 显示用户前面输入的个人基本信息 -->
		<mx:Form>
			<mx:FormHeading label="Review and Checkout"/>
			<mx:FormItem label="Name">
				<s:Label text="{orderInfo.billingName}"/>
			</mx:FormItem>
			<mx:FormItem label="Address">
				<s:Label text="{orderInfo.billingAddress}"/>
				<s:Label text="{orderInfo.billingCity}, {orderInfo.billingState} {orderInfo.billingZip}"/>
			</mx:FormItem>
			<mx:FormItem label="Card Type">
				<s:Label text="{orderInfo.cardType}"/>
			</mx:FormItem>
			<mx:FormItem label="Delivery Date">
				<s:Label text="{orderInfo.deliveryDate}"/>
			</mx:FormItem>
			<mx:FormItem>
				<s:Button label="Complete Order" click="handleComplete( event )"/>
				<s:Button label="Edit Information" click="handleEdit( event )"/>
			</mx:FormItem>
		</mx:Form>
		
		<!--将购物车的详细信息进行显示-->
		<s:VGroup width="100%" height="100%">
			<components:CartGrid id="dgCart" 
								 width="100%" height="100%" 
								 dataProvider="{shoppingCart.items}"
								 removeProduct="removeProductHandler( event )"/>
			
			<s:Label text="Total {shoppingCart.total}"/>		
		</s:VGroup>
	</s:HGroup>
</s:NavigatorContent>

你可能感兴趣的:(flex4)