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>