FLEX核心开发技术(FLEX大局观)

学习一门语言或者技术,我们不仅仅需要关心具体的应用细节,很多时候我们需要跳出这些细节,用全局的目光去纵观它,这样可以获得更好的理解,更深入的认识。

在我们应用FLEX开发的过程中,构建表现层布局,MXML编程和ACTIONSCRIPT基本上都可以满足我们的需求,那么MXML和ACTIONSCRIPT分别的侧重点又是什么呢,或者换一种表达方式,MXML和ACTIONSCRIPT分别的长处和短处又是什么呢。为了分析这个问题,我们引用在企业级开发中的另一种相似的情景,尤其是对J2EE熟悉的开发者来说,就是JSP和SERVLET的角色和使命。

JSP从本质上来说是SERVLET的另一种表达方式,都是以单例的形式多线程的响应客户端请求。从编译角度来说,JSP首先会被转换成SERVLET的形式,以CLASS字节码文件等待JAVA虚拟机JVM的最终解析和执行。JSP更擅长从最终用户的角度构建系统的表现层,而传统的SERVLET则更擅长业务逻辑的处理。反观我们的MXML和ACTIONSCRIPT,其所处的角色和相对的关系与JSP和SERVLET有着及其的相似性。MXML以标签的方式来布局最终用户的表现层,MXML类实际上是ACTIONSCRIPT类的另一种表现方式,之所以会有这种表现方式,是因为它能够及其方便开发者快速的构建用户的表现层,而没有必要在ACTIONSCRIPT脚本中以硬编程的方式来实现布局,尤其是复杂的页面布局。编译期,MXML也会以ACTIONSCRIPT文件为中间形态,最后形成SWF字节码供AVM虚拟机解析和执行。

MXML可以快速的构建表现层页面是其优点之一,另外还有一点,就是MXML本身的数据绑定机制的实现。这一点可以让我们很好地封装和隔离页面代码和逻辑代码,为和服务器端的集成提供了很基础的保证。

在理解了Flex编程语言之后,我们来从下面的几个方面去体会Flex的大局,Flex的核心技术在我眼中也就大概是以下几大技术。

1,利用容器类布局表现层

MXML标准实现包括了两种类型的组件,控件和容器。控件一般指TextInput, Label,Button等实体页面元素。相应地,容器一般指一块长方形的空间,在这个空间里可以按照当前这个容器预定义的放置规则放置控件和别的容器。在种类上容器分布局性容器和导航性容器两种。

上面我们提到容器的放置规则,那么什么是放置规则呢?我们现在讨论这个话题。举个例子,对于中国象棋和国际象棋来说,棋子的摆放和挪动规则是不一样的,我们不能在中国象棋的棋盘上玩国际象棋。MXML容器内页面元素的放置规则可从总体上分为以下几种。

一.横向或纵向规则。

在FLEX所有的标准容器内以字母H或V打头的容器组件基本都属于这种规则,如Hbox,/Vbox,HdevidedBox/VdevidedBox, 它们在本质上是近亲,有着共同的祖先Box。
在Box容器中有个direction属性,可以设其为horizontal或者vertical,在功能上和Vbox和Hbox一摸一样。实际上,Vbox和Hbox就是direction属性已经初始化为horizontal或者vertical的Box。
在实现上HdividedBox/VdividedBox分别是direction属性已经被预设为horizontal和vertical的DividedBox。DividedBox比其父亲Box多了一个可以通过拖动重新设定容器大小的属性。

二.网格式规则。

在FLEX标准组件库中利用网格式布局孩子元素的主要有Grid和Tile两个。所谓网格式布局就是指在一个长方形的容器空间内按照预设的行数和列数对空间进行打格子划分,孩子元素可被放到相应的格子中去。Grid容器利用配套的GridRow和GridItem元素来设置网格布局。
Tile则默认以最大的孩子组件的大小为标准,以相同的高度和宽度来布局它的孩子组件。也可以通过cellWidth和cellHeight属性设定孩子元素的大小。

三.坐标式规则。

在FLEX标准容器组件中采用显示绝对坐标布局孩子元素的容器是Canvas组件,它通过孩子元素的x和y属性来设定其在Canvas长方形空间内的位置。

四.点缀式规则。

所谓点缀式规则,实际上是指当前容器参与同级容器的布局中,只是起点缀的作用,其大小不会影响到它点缀对象的大小的一种容器,比如ControlBar和ApplicationControlBar,都一般和Panel容器或者TitleWindow容器一起出现扮演点缀的角色。ApplicationControlBar 通常被用来格式化页面布局的顶端,如顶部主菜单栏、顶部按钮等。它也通常和Panel或者TitleWindow一起使用。

五.复用式规则。

所谓复用规则是指,在某些容器的长方形空间内,所有的孩子元素中在某一时刻只有一个处于显示状态,其他的都处于隐藏状态。基本所有的导航式容器都遵循这种规则。导航类容器在功能上不具有布局类容器的特性,它基本上都是以分层的方式共享同一块容器空间(孩子元素的状态分为两种显示和隐藏),并通过设定其内置的selectedChild或者selectedIndex属性的方式在不同的层之间导航。为充分利用有限空间提供了很好的方案。导航类容器主要分为:Accordion,TabNavigator,ViewStack。

六.其他

在FLEX的标准容器库内有三个特例,分别为Application, Panel和TitleWindow。说特殊是因为它们的布局方式默认为纵向布局。但是它们都有一个layout属性可以分别指定为vertical,horizontal和absolute.当layout属性设置为vertical时就像Vbox,当为horizontal时,布局方式就是一个Hbox,而当是absolute时,就变成了一个Canvas.就是说它们的布局方式包含纵向横向规则和坐标式规则。

2,利用控件展示页面内容

FLEX标准组件库中有几十种丰富的控件库,有了这些搭配容器组件我们可以很方便的建立起十分绚丽的表现层界面,使我们的RIA应用真正地富起来。所有的控件类以及容器类都有共同的祖先UIComponent,我们将在后续自定义组件章节里详细分析这个祖先的行为和属性。读者大可以参考ADOBE官方示例浏览这些丰富的控件分别可以做些什么。

3,FLEX名字空间

从字面上来讲,采用名字空间的最大的一个好处是避免类名字冲突,第二个好处是实现逻辑有效隔离。FLEX名字空间的展现方式主要分为两种,一种是在MXML根标签内;另一种是在ACTIONSCRIPT的包名字定义中。我们在每一个MXML文件的根标签内都要声明至少一个FLEX标准类库的名字空间,如
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
Xmlns就是 XML NAME SPACE ,是XML名字空间的意思。冒号后面的mx是一个名字空间的索引,后面双引号内的内容就是FLEX标准类库的SCHEMA。在MXML自定义组件中我们也必须指定名字空间。如名字为CustomizedCombox.mxml的自定义组件,定义在{$CLASSPATH}/com/broadview/flexpractice/chapter3下面。
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">
     <mx:dataProvider>
        <mx:String>1</mx:String>
        <mx:String>2</mx:String>
        <mx:String>3</mx:String>
        </mx:dataProvider>
</mx:ComboBox>
那么定义好自定义组件以后,该怎么用呢?第一步应该在引用文件中加入自定义组件的名字空间。如
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:customized="com.broadview.flexpractice.chapter3.*">
        <mx:Panel  title="LAYOUT Example" status="Active" height="185" width="537" layout="absolute" >
        <mx:Button label="BUTTON1" />
        <mx:Button label="BUTTON2"  x="33" y="41"/>
        <mx:Button label="BUTTON3"  x="118" y="81"/>
        <mx:Button label="BUTTON4" />
        <mx:Button label="BUTTON5" />
        <customized:CustomizedCombox id="customizedCom"/>
    </mx:Panel>
</mx:Application>
这里我们随意指定了这个自定义组件的名字空间的索引为customized,它所指向的为FLEX应用的CLASSPATH下该组件所在的包全名。那么在用这个组件是,是这样写的。
<customized:CustomizedCombox id="customizedCom"/>
所以通用的格式为
<namespace:ClassTag id ="id name"></namespace:ClassTag>
如果没有定义这个namespace,就是匿名名字空间 如
xmlns="com.broadview.flexpractice.chapter3.*"
那么在引用时就变成了
<ClassTag id ="id name"></ClassTag>
以上我们具体地讲解了在mxml中定义和利用名字空间的方法。相对地,在ACTIONSCRIPT类中也会用到名字空间。首先类定义的时候需要指定当前类所在的类包,也就是它的名字空间。再者,如果在类的定义中要关联、组合、聚合、合成到别的类包中的别的类,我们必须要用import关键字显式地导入这个类的名字空间。如果没有导入,在用到这个类时就必须在这个类前加上这个类的名字空间作为前缀。在后面我会专门贴出些关于as中使用命名空间的文章。

4,数据绑定概念

数据绑定是FLEX中一个全新而强大的概念,数据绑定机制允许在整个FLEX客户端应用的范围内,对于任何一个对象或其属性绑定了任何别的的对象或属性,当源对象(被绑定对象)的值改变时,目标对象(绑定对象)的值也相应的改变。如对象A绑定了对象B,当对象B的值发生了变化,那么同步地,对象A的值也会改变。绑定是这样一种拷贝触发器的概念,源对象的值变化时,触发器被触发,进而紧接着一个从变化后的源对象值到目标对象值的拷贝动作。另外绑定并不是任意的,标准只有一条就是绑定的源对象和目标对象数据类型应该相同。
FLEX中提供了三种数据绑定方式供开发者选择,它们分别是

一.通过大括号{}实现绑定。

这个相对来说用的最多,也是最简单的相信大家都用过,这里就不再阐述。

二.通过标签实现绑定。

<Binding source="dataSet" destination="chart.dataProvider"/>
source 源数据,destination 目标数据

三.通过mx.binding.utils.BindingUtils类实现绑定。

BindingUtils共有两个公共方法bindProperty()和bindSetter(),分别用来绑定对象属性和绑定函数输入参数。
绑定对象属性例子:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  creationComplete="init()">
    <mx:Script>
      <![CDATA[
        import mx.binding.utils.*;
        public function init():void {
            BindingUtils.bindProperty(q1, "text", q2, "text");
        }
      ]]>    
    </mx:Script>
    <mx:TextInput id="q1"/>
    <mx:TextInput id="q2" />
</mx:Application>
ID为q2的text属性被绑定到ID为q1的text属性上,也就是说当往q2输入任何东西,q1都同步地跟随变化。这就是所谓BindingUtils的属性绑定。
绑定函数输入例子:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  creationComplete="init()">
    <mx:Script>
      <![CDATA[
        import mx.binding.utils.*;
        public function init():void {
            BindingUtils.bindSetter(doSomething,q1,"text");
        }
        public function doSomething(text:String):void{
              q2.text = text.length+'';
        }
      ]]>    
    </mx:Script>
    <mx:TextInput id="q1"/>
    <mx:TextInput id="q2" />
</mx:Application>
应用初始化时init方法被调用里面调用BindingUtils的bindSetter方法,将q1的text属性绑定到函数doSomething的输入形参text上,并调用doSomething方法在q2中显示q1输入的字符长度。

5,RPC远程业务

FLEX提供RPC远程过程调用以便远程存取服务端数据集或者更新数据到远程服务端。本身FLEX有几种类型的RPC远程业务,如可以通过简单对象存储协议SOAP访问WEB SERVICE;通过AMF(Action Message Format)访问驻留在服务端的JAVA对象;或者通过HTTP URL获取服务端XML格式化数据。FLEX封装了所有的RPC远程业务到MXML标签中,也就是说我们可以在MXML标签或者ACTIONSCRIPT中定义我们的远程业务访问逻辑。它们分别为,

一,WEB SERVICE组件,通过SOAP协议远程访问服务端。

二,HTTPService组件,通过HTTP URL远程访问。

三,Remote Object 组件,这是Flex各RPC业务中最常用到的方式,因为它可以通过AMF协议,远程访问服务端的各种类型对象,如JAVA,PHP,.NET等。

具体的例子可以参考官方说明文档,或者Google资料非常的齐全。

6,数据格式化和数据验证

原则上我们经常会对表单做数据验证,尤其对数据的格式有要求的时候,这个过程应该在客户端完成,没有必要提交不合格的数据到服务器端验证。FLEX提供多种数据验证组件,如字符串验证,日期验证,电话号码验证等等。FLEX的标准验证组件中有三个经常用到的属性和一个函数,它们分别是,required属性绑定一个布尔值,用于说明当前绑定验证对象是必须不为空的还是可以为空;source属性用于指定被绑定的验证对象ID如TextInput组件的ID等;property属性用于指定对被绑定对象的那个属性进行验证如TextInput的text属性等。一个函数是验证组件的validate()方法,此方法执行后会触发一个验证结果事件ValidationResultEvent,通过检测这个事件的类型为有效ValidationResultEvent.VALID或者是无效ValidationResultEvent.INVALID来最终判断是否提交数据到后台服务端。
Flex的标准类库还包含了一些数据格式化组件,它们的行为总是这样的。就是,预先指定这个格式化组件的合适规范,一般都通过stringFormat属性来指定。格式化动作通过调用其公共方法format()来实现,输入参数为一个粗粒度的对象,格式化后的结果遵循stringFormat定义的schema。

7,样式表CSS

在HTML中我们经常会用CSS样式表统一设定页面元素的风格。同样地,FLEX也用CSS样式表来风格化页面元素。在FLEX的应用中可以用

8,EFFECTS行为

在FLEX开发过程中我们为了优化应用的响应方式,通常要对EFFECTS行为类进行操作。FLEX本身提供了若干标准的EFFECTS类,如,ZOOM,FADE等。EFFECTS类通常被一些用户动作触发,如鼠标移动,键按下,得到焦点等等。关于EFFECTS的话题大体可分为三个方面。

一 事件触发EFFECTS

二 以声明的方式自定义EFFECTS

三 以编程的方式自定义EFFECTS


9,自定义组件

Flex组件开发可分为两种. 一是在mxml中创建自定义组件.另一种则在actionscript class中创建. 总体说来其实大同小异. 首先我们要转换一种观点. mxml组件文件和ActionScript class文件一样都是类.开发者都可以在语法和机制上new 这个类的. 比如两个一模一样的组件.MyButton.mxml 和 MyButton.as. 当我们想要在某一个as函数中动态的创建这个自定义按钮时,都可以.
public var tempButton:MyButton = new MyButton();
parentPanel.addChild(tempButton);
当我们自定义组件时,有若干问题要注意.
1. 如果我们想要给这个新组件添加一个属性,只要在组件类中声明这个变量为public就可以了.
2. 如果想要给这个组件添加一个自定义事件,只要在组件类定义这个Event然后addEventListener就可以了.
3. 如果此组件需要一些Util工具函数,只要在组件定义类内部把这个工具函数public static就可以了.
4. 如果你的组件比较复杂并且存在数据相互依存,那么建议最好将组件的createPolicy设置为"all", default为"auto"。
在ACTIONSCRIPT中定义一个扩展的TextArea组件CustomTextArea,用来监控键盘按键操作。代码为
package com.broadview.flexdevpractice.chapter3
{
    import mx.controls.TextArea;
    import flash.events.KeyboardEvent;
    public class CustomTextArea extends TextArea {
        public function CustomTextArea() {
            super();
            addEventListener("keyDown", keyDown);  
            addEventListener("keyUp", keyUp);   
        }       
        private function keyDown(eventObj:KeyboardEvent):void {           
                text = eventObj.charCode+''; 
        }
        private function keyUp(eventObj:KeyboardEvent):void {           
                text += eventObj.toString()+'\n'; 
        }
    }
}
主应用文件代码,注意名字空间的引用。
<?xml version="1.0"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    xmlns:Comp="com.broadview.flexdevpractice.chapter3.*">
    <Comp:CustomTestArea id="customArea"  height="282" width="322"/>
</mx:Application>
 
来源于:Mr.8