Flex3开发指南
有关ActionScript 3的部分,请观看本人总结的ActionScript 3详解文章!
1.Flex 3是Adobe出品的开发RIA(Rich Internet Application富互联网应用)的工具,Flex 3包括:Flex 3 SDK软件开发包、编译器、Flex类库和调试工具。
2.Flex Builder 3是基于Eclipse之上的一个开发工具,界面和使用方法很类似Eclipse。
3.Flex的应用程序到底是什么东西?
*答:其实就是把可以用Flash播放的swf格式文件封装到了HTML页面中的应用程序,
然后程序(可以认为HTML)就可以借助Flash文件(swf)的功能(如事件等)来和服务器端进行交互。
*注意:要运行Flex的应用程序必须在客户端安装Flash Player 9或以上的播放器才行;
如果没有安装,那么打开Flex的应用程序时,IE下会提示通过ActiveX插件的形式在线安装。
4.Flash Player 9安装时会有两种版本:非调试版本和调试版本。非调试版就不用说了就是用来运行Application应用的;
*调试版的作用:********************后边讲到
5.Flex 3 Application应用的实现方式:主要借助MXML文件和ActionScript 3语言(AS3)来实现。
*MXML的作用:该文件为一个描述文件,非常类似于XML,只不过该文件中的标签都要以"mx"开头(因为名称空间指定),例如<mx:xx> 。
且该文件的根元素为<mx:Application> ,说白了就是通过这个文件来定义Flash的swf格式文件,
只不过编译后就直接将生成的swf封装到了满足"一定格式"的HTML文件中了。
**注意:我们知道Flash文件中只能有ActionScript代码,没听说过也可以有MXML文件,
所以Flex中的这个MXML文件只是为了方便视图界面的开发和格式的美观优雅而特别订制的,
其实运行Flex的应用时,首先会将MXML文件中的定义内容转换成相对应的ActionScript代码(变量、对象等),
然后在运行所有ActionScript代码,也就是说如果有MXML的内容的话就先把它们转换成ActionScript,
然后将原来的ActionScript和刚转换成的ActionScript一起进行编译(编译后的文件默认会输出到bin-debug目录),使之作用于Flash文件之上。
**注意:在MXML文件中只能在<mx:Script>...</mx:Script>标签内部使用<![CDATA[ ActionScript代码 ]]>段的形式书写ActionScript代码,
不能像在as文件中那样写ActionScript代码。
*ActionScript 3的作用:就如上说,就是用来定义Flash文件(swf)中的对象、事件等组件的语言。
**技巧:由上边说明知道ActionScript代码会在MXML文件内容转换完后才一起执行,
这样一来就可以在ActionScript代码中直接引用MXML文件中通过元素定义(MXML会将元素的ID值最为定义的对象名称)的对象了,
无需担心会访问不到,因为现将MXML转换成ActionScript,然后在统一编译执行ActionScript代码,最后生成封装有swf文件的HTML等一些文件。
**注意:一般Flex应用中会将MXML和ActionScript这两种方式结合使用,以达到最佳效果。
6.Flex Builder 3提供了3种类型的项目:Flex项目、Flex库项目和ActionScript项目。
*Flex项目:就是我们要使用的。我们可以在项目中导入我们自己定义的Flex类库SWC文件(类似与Java中的jar包)。
它有一个html-template目录,存放的是模板文件,输出到bin-debug目录中的文件就是以html-template目录中模板文件为模板生成的。
所以修改html-template模板中的某个设置将会影响输出的内容,有的时候为了实现某个界面效果可以修改模板文件。
**注意:SWC库(库中可以封装图片、声音等素材文件、程序(组件或自定义组件)等)文件类型分为普通类型和RSL类型,
虽然都是库包,但是前者使用时一般要封装到swf文件中使用,就是不需另外导入对应的SWC库包;而后者就是使用RSL机制,
让swf文件在使用SWC库中的内容时才运行(加载SWC库包),所以需要导入SWC库包到项目,这种属于动态机制。
*Flex库项目:就是将要封装的内容放到src中,然后编译项目,就会在bin目录中生成对一个的SWC库文件。
*ActionScript项目:就是编写ActionScript语言对应的.as文件,然后编译生成对应的SWC库包,供Flex项目导入使用。
7.使用MXML来实现事件处理机制:用一个例子来演示。
<1>首先创建一个MXML Component文件,使用已有的ActionScript组件来组装一个自定义的组件。
其实就是创建一个新类,继承已经存在的组件(如Panel),然后在自定义类中封装几个已存在的组件作为属性,以组成自己的类!!
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="后台管理">
<mx:Label x="41" y="30" text="用户名:"/>
<mx:Label x="41" y="76" text="密 码:"/>
<mx:TextInput id="t_username" x="119" y="28" borderColor="#0B65A4" backgroundColor="#CE6363" backgroundAlpha="0.18"/>
<!-- displayAsPassword="true"表示输入密码后用黑点儿显示 -->
<mx:TextInput id="t_password" x="119" y="76" displayAsPassword="true" borderColor="#0B65A4" backgroundColor="#CE6363" backgroundAlpha="0.18"/>
<!-- 为按钮注册鼠标点击监听器事件方法clickButton -->
<mx:Button x="119" y="123" label="登陆" width="72" click="clickButton()"/>
<!-- 这里不是为该自定义组件注册一个Event事件,而是指定该组件可以注册这个事件,事件类型叫做"login" -->
<mx:Metadata>
[Event (name="login", type="flash.events.Event")]
</mx:Metadata>
<!-- 点击按钮触发事件方法后,为整个自定义组件的事件流中添加一个新的上边声明了的login类型的事件
此事件添加到事件流后,如果自定义组件或子节点组件有注册login类型的监听器,那么会立即触发-->
<mx:Script>
<![CDATA[
internal function clickButton():void{
//向这个组件的事件流中制造一个新的事件,以便可以触发对应的监听器
this.dispatchEvent(new Event("login"));
}
]]>
</mx:Script>
</mx:Panel>
*说明:因为表单有登陆按钮对象,所以要为按钮注册一个"登陆事件‘(即鼠标点击事件),
当点击时当然就会触发事件监听方法,进而完成对应的功能(判断用户名、密码等)。
*注意: 这样一个自定义组件不能独立运行,只能供一个MXML文件引用而使用。
所以是否触发login类型的事件要看引用该组件对象的MXML文件中的声明了。见下边!!
<2>在MXML文件中引入自定义组件,使用<ns1:LoginForm>元素引用(也可以从组件视图上拖动)。
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:ns1="*">
<!-- 事件监听方法,当自定义组件有login类型的事件发生时,就会调用loginClick()方法 -->
<mx:Script>
<![CDATA[
import mx.controls.Alert;
//监听器方法
internal function loginClick(evt:Event):void{
Alert.show("登陆成功","提示");
}
]]>
</mx:Script>
<!-- 在MXML中引入自定义组件,并且为组件注册login类型的事件监听器,监听方法为loginClick,参数一定要传入event对象,
之所以要传入参数是因为声明的事件监听方法要接收这个参数 -->
<ns1:LoginForm id="loginForm" login="loginClick(event)" verticalAlign="middle">
</ns1:LoginForm>
*说明:login="loginClick(event)"中的login是事件类型,而loginClick则是事件监听器方法
</mx:Application>
<3>总结: 上边例子中,首先在自定义组件中为自定义组件声明了一个可以使用的事件类型"login",
然后为自定义组件中的按钮的鼠标点击事件注册监听器方法为clickButton()方法,方法体中是为自定义组件的事件流中制造一个login类型的事件。
也就是说运行时,点击按钮后,会触发clickButton方法,然后该方法为自定义组件事件流中制造一个新的login事件,
这回导致注册了login事件类型的监听器被调用,即loginClick被调用。这是上边例子点击登陆后的操作流程。
<4>上边为自定义组件声明的事件类型都是ActionScript提供的事件Event类型的,我们当然也可以想在ActionScript中那样,定义自定义的事件类型。
//自定义事件类型
public class LoginEvent extends Event{
//保存用户名
public var username:String;
//保存密码
public var password:String;
public function LoginEvent(type:String){
super(type, false, false);
}
}
*修改<1>中代码:
<mx:Metadata>
<!-- type的值改成了自定义事件类型 -->
[Event (name="login", type="com.events.LoginEvent")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import com.events.LoginEvent;
internal function clickButton():void{
//创建自定义事件对象,并且指定类型名为"login"
var loginEvent:LoginEvent = new LoginEvent("login");
//得到用户名值
loginEvent.username = t_username.text;
//得到密码值
loginEvent.password = t_password.text;
//向事件流中制造事件
this.dispatchEvent(loginEvent);
}
]]>
</mx:Script>
*修改<2>中代码:
//此处参数类型改成了LoginEvent自定义类型,如果不改将会得不到username和password属性值
internal function loginClick(evt:LoginEvent):void{
//判断用户名和密码
if((evt.username == "admin") && (evt.password == "admin")){
Alert.show("登陆成功","提示");
return;
}
Alert.show("登陆失败","警告");
}
*说明:其实我们可以直接在按钮的鼠标点击事件中进行表单的验证,不过如果这样代码的复用能力就比较差,
因为我们可能会在很多地方都会使用自定义组件,如果验证写在鼠标单击按钮事件方法中,那么在每一次引用自定义组件后,
如果各个需求的验证方法不同,那么就要总是修改自定义组件的鼠标点击事件方法中的代码了。
而向上边那样写,就无需修改自定义组件中的代码了。
8.数据绑定: 就是当数据源对象的数据发生变化时,目标对象的数据会自动更新,而不需要我们再编写代码去强制更新。
* 绑定的内部原理: 绑定实际也是借助事件机制来完成的,当目标使用了数据绑定的时候,
目标对象就会监听数据源对象的某一固定事件。当数据源发生变化时,数据源就会制造出那个固定的事件(ChangeEvent事件),
此时目标对象的监听机制会被触发,即通知目标对象更新数据。不过这个过程都是由Flex完成,不用我们手动干预!!
* 绑定的前提条件: 数据源对象的数据和目标对象的数据格式相同。
<1>方法一 : 针对MXML文件可以使用的方法。在为组件对象的元素属性赋值时,使用"{}"直接将数据源直接绑定到对象组件的某个属性上,这样就可以了。
例子:
<!-- 绑定语句 : fontSize="{h_slider.value}" -->
<mx:Label id="f_label" x="319" y="61" text="滑动条数据绑定" fontSize="{h_slider.value}"/>
<mx:HSlider id="h_slider" x="276" y="284" minimum="20" maximum="40" snapInterval="10"/>
说明:当滑动条滑动时,将会改变滑动条的数值,因为我们将<mx:Label>的fontSize属性值和滑动条的数值进行了绑定,
所以滑动条变化后的数值将会作为<mx:Label>的fontSize属性值。
<2>方法二 : 针对MXML和ActionScript结合使用的方法。
在组件对象的元素属性中,使用"{}"把某个ActionScript的方法的返回值作为数据源绑定到该组件对象属性上。
同时ActionScript的这个方法的参数要使用[Bindable]绑定符号。
例如:
<mx:Script>
<![CDATA[
//作为方法的参数, 如果不指定[Bindable]那么参数变化后不会通知目标进行更新数据
[Bindable]
private var number:int;
//下边调用的方法,做平方运算
internal function square(num:int):int{
return num * num;
}
]]>
</mx:Script>
<mx:Label x="276" y="244" text="结果" fontSize="17" id="f_label"/>
<!-- 这里把square方法的返回值作为数据源,而number属性作为参数进行绑定,有规则知道作为参数的number属性要使用[Bindable]进行声明,
表明为该属性指定一个监听器(由Flex自己完成),当属性值变化时就表示触发该事件,然后就会通知数据绑定目标进行更新操作(也是由Flex自己完成) -->
<mx:TextInput x="323" y="249" width="113" text="{square(number)}"/>
<!-- 这里把滑动块的值作为数据源,目标对象为通过ActionScript定义的number属性;
当滑动条变动的时候会触发change属性指定的方法,不过这里不是方法,而是数据绑定,
当变化时会将滑动条的值赋值给通过ActionScript定义的number属性变量 -->
<mx:HSlider x="276" y="284" id="h_slider" minimum="1" maximum="10" change="{number = h_slider.value}"/>
**补充关于[Bindable]的知识 :
**声明的标准格式 : [Bindable(event="eventType")] 表示为添加该声明的属性(数据源)制造事件,就是说当数据源变化时,
向事件流中制造一个事件,以便触发事件(Flex内部定义好的)去通知目标对象进行更新操作(由Flex完成)!!
**我们上边为什么只是指定了[Bindable]呢? ---- 因为如果不指定默认值为[Bindable(event="propertyChange")],等价于[Bindable],
就是说当属性改变的时候制造一个事件,以便Flex通知目标对象进行更新操作。
**扩展能力补充: [Bindable]不仅可以用在属性上,也可以用在getter或setter方法(2选1即可)上,也可以作用在类的声明上。
A.作用在getter或setter方法上: 成为方法级绑定。实现的效果和[Bindable]作用在属性上差不多。
例子:
//1.创建一个ActionScript的类
public class BindClass{
//属性处则不用进行绑定了
private var age:int;
//建立绑定关系
[Bindable]
public function get Age():int{
return this.age;
}
//属性的setter方法,[Bindable]作用在getter或setter方法中选其一即可
public function set Age(age:int):void{
this.age = age;
}
}
//2.在MXML文件中使用BindClass类
<mx:Script>
<![CDATA[
//定义一个类对象,供下边的MXML文件访问
private var bc:BindClass = new BindClass();
//下边调用的方法,做平方运算
internal function square(num:int):int{
return num * num;
}
]]>
</mx:Script>
<mx:Label x="276" y="244" text="结果" fontSize="17" id="f_label"/>
<!-- 因为BindClass绑定的是getter和setter方法,
所以暴漏出来的是get或set关键字后边的部分(可以作为属性直接使用),
不过此时就不能直接访问BindClass类的age属性,因为并没有绑定age属性,
下边text="{square(bc.Age)}"中的bc.Age表示调用的是get Age()方法 -->
<mx:TextInput x="323" y="249" width="113" text="{square(bc.Age)}"/>
<!-- change="{bc.Age = h_slider.value}"中的bc.Age表示调用的是set Age()方法-->
<mx:HSlider x="276" y="284" id="h_slider" minimum="1" maximum="10" change="{bc.Age = h_slider.value}"/>
B.作用在类的声明上: 称为对象(类)级别绑定,[Bindable]标签用于公有类时,
这个类的所有public类型的变量和setter、getter方式定义的方法都可以用于绑定。
例如:
//1.创建一个BindClass类型,并且绑定类级别的绑定
[Bindable]
public class BindClass{
<!-- 下边的 属性 会因为定义了类级的绑定自动进行绑定 -->
//定义成public主要使用与演示效果
public var age:int;
<!-- 下边的 getter或setter方法 会因为定义了类级的绑定自动进行绑定 -->
//getter方法
public function get Age():int{
return this.age;
}
//属性的setter方法,[Bindable]作用在getter或setter方法中选其一即可
public function set Age(age:int):void{
this.age = age;
}
}
//2.在MXML文件中使用BindClass类: 此时就可以使用A中或第一种方法来实现了。
<mx:Script>
<![CDATA[
//定义一个类对象,供下边的MXML文件访问
private var bc:BindClass = new BindClass();
//下边调用的方法,做平方运算
internal function square(num:int):int{
return num * num;
}
]]>
</mx:Script>
//可以使用这种方案,也可以使用下边的(就是第一种方式)
<mx:Label x="276" y="244" text="结果" fontSize="17" id="f_label"/>
<mx:TextInput x="323" y="249" width="113" text="{square(bc.Age)}"/>
<mx:HSlider x="276" y="284" id="h_slider" minimum="1" maximum="10" change="{bc.Age = h_slider.value}"/>
或
<mx:Label x="276" y="244" text="结果" fontSize="17" id="f_label"/>
<mx:TextInput x="323" y="249" width="113" text="{square(bc.age)}"/>
<mx:HSlider x="276" y="284" id="h_slider" minimum="1" maximum="10" change="{bc.age = h_slider.value}"/>
<3>方法三 : 使用<mx:Binding>标签来实现,source属性用于指定数据源,destination用于指定目标对象。该标签要和<mx:Model>标签组合使用,
把<mx:Model>指定的数据作为<mx:Binding>的数据源。
** 内容补充: 标签<mx:Model>的使用,就是可以在该标签内部定义一些数据,定义形式和XML一样。
例如: <!-- 标签中定义了一个<books>标签和两个兄弟标签<book> -->
<mx:Model id=“books”>
<books>
<book>
<name>FLEX教程</name>
<author>张三</name>
</book>
<book>
<name>JAVA高级编程</name>
<author>李四</name>
</book>
</books>
</mx:Model>
** 实现方法:
//把上边的<mx:Model>作为数据源,这里source="books.book.name"中的books指的是<mx:Model>中的id值(该对象就表示根元素),
//所以books.book就是得到<books>下的所有<book>以数组的形式(第一个元素下标为0,取0的时候可以不指定下标)。
//destination="text_name.text"则是将数据源中的数据传到目标对象上。
<mx:Binding source="books.book.name" destination="text_name.text"/>
//<mx:Binding source="books.book[0].name" destination="text_name.text"/>与上边的等价
//表示目标对象
<mx:TextInput x="276" y="135" id="text_name" fontSize="16" fontWeight="bold"/>
//结果说明: 显示"Flex教程"
<4>以上三种方法总结: 三种绑定的方法一般都是绑定的静态数据,就是都是在文件中准备好了的数据!!
<5>Object对象和动态对象: ActionScript中的Object对象和Java中的有区别,在ActionScript中Object是一个动态对象,可以为对象动态指定属性。
例如:
var obj:Object = new Object();
obj.name = "admin"; //动态指定属性name并为其赋值
obj.age = 24; //动态指定age属性
obj.address = "北京海淀区万泉庄"; //动态指定address属性
或者: 进行初始化
var obj:Object = {name:"admin", age:24, address:"北京海淀区万泉庄"};
**注意:可以使用"dynamic"关键字来定义一个动态的类型,使用的时候可以向上边Object一样,可以动态创建属性。
**说明:<mx:Model>标签运行时会被转换成ActionScript语言中的Object类型的对象,因为Object是动态对象,
所以像source="books.book.name"这样指定数据源的时候,如果指定了错误的属性,并不会报告错误,因为是动态类型,
如果指定错误他会动态创建这个属性,所以将会导致匪夷所思的不可预见性的错误,为此Flex内部实现的时候当把<mx:Model>转成Object的时候,
Flex又紧接着将Object转换成了ObjectProxy类型的对象,就是去除了Object的动态类型功能的包装代理类,这样才得以上边的程序运行没有后顾之忧!!
<6>工具类BindingUtils和动态绑定: mx.binding.utils.BindingUtils类
(API文档中没有该类的帮助,可以从Flex Builder的帮助中查看API文档,也可在Flex Builder创建的类中按F1快捷键)
中提供了两个静态方法来处理动态绑定!!
**例子1: 需求要求动态创建一个Label对象,然后将它加入到应用程序中(相当于加入到Java Swing的Frame窗体中)。
而之前的方法是使用MXML创建一个<mx:Label>,这样可以使用上边的方式进行绑定,而这里要求动态创建一个Label对象,
此时就是动态绑定,要借助BindingUtils.bindProperty()方法来进行动态绑定。
<mx:Script>
<![CDATA[
//定义一个Label类对象
internal var label:Label = new Label();
//初始化方法,运行应用程序时自动运行该方法
internal function init():viod{
//将动态创建的label对象添加到应用程序窗体
this.addChild(label);
label.x = "300"; //设置label对象的属性值
label.y = "100";
label.width = "200";
label.height = "50";
label.text = "10"; //刚开始Label中显示10这个数字
//为label对象动态绑定,将滑动条的value属性和该label对象的text属性进行绑定
BindingUtils.bindProperty(label, "text", text_show, "value");
}
]]>
</mx:Script>
<mx:HSlider id="text_show" x="276" y="284" minimum="20" maximum="40" snapInterval="10"/>
**例子2: BindingUtils.bindSetter()方法的应用。修改上边的例子!
BindingUtils.bindProperty(label, "text", text_show, "value");修改成
BindingUtils.bindSetter(setTxt, text_show, "value");意思是当text_show组件对象的value属性值发生改变时,要调用setTxt()方法,
调用的同时将text_show对象的最新value属性的值作为参数传给setTxt()方法。
除了修改上边语句外,还要添加一个setter方法,其实该方法的定义名称可以随意,不过这里为了见名知意,就定义成了setTxt()名称!!
internal function setTxt(txt:String):void{
label.text = txt; //将Label对象的text属性值等于最新版本的text_show的value属性值
}
9.Flex的样式(style): 使用方式有多种。
<1>直接使用CSS文件,系统默认使用default.css文件。
引入格式 : <mx:Style source="要引入的CSS文件的路径名(相对/绝对都行)"/>
<2>使用Flex的视图编辑器模式,直接操作组件对象的style样式!!
<3>如果是动态创建的组件对象,那么可以通过调用对象的setStyle()方法来设置样式,也可通过getStyle()方法得到样式!!
<4>使用StyleManager类来操作样式: 结合CSSStyleDeclaration类一起使用!!
例如:
<mx:Script>
<![CDATA[
internal function init():void{
//创建一个样式对象
var cs:CSSStyleDeclaration = new CSSStyleDeclaration("myCssStyle");
cs.setStyle("color", "#000000"); //设置样式对象的颜色属性为#000000色
//将cs样式对象作用与程序中所有Panel类型的对象上
StyleManager.setStyleDeclaration("Panel", cs, true);
}
]]>
</mx:Script>
*说明: MXML文件中的标签引用CSS文件中定义的样式的时候一般使用styleName属性来引用!!
<5>定义CSS文件的格式:
/* 全局样式,使用global关键字定义,就是对所有具有以下指定的属性(像borderColor属性)的标签,它们的对应属性值都是#767473 */
global
{
borderColor: #767473;
}
**注意:在ActionScript代码中可以使用
var globaalStyle:CSSStyleDeclaration = StyleManager.getStyleDeclaration("global");来得到全局样式对象,
在程序中可以动态的修改对应的样式属性的值!!
/* 作用于<mx:Application>标签及其子标签的样式 */
Application
{
borderStyle: "none";
}
/*
可以使用MXML文件中标签的styleName属性来引入这个样式,例如,styleName="comboDropDown"其中"."不用写入
类似于HTML中CSS中的类选择方式,HTML标签中可以使用class属性来指定这种类型的CSS样式定义!!
*/
.comboDropDown
{
backgroundAlpha: 0.6;
}
10.Flex的主题: 主题是一套配置完整的CSS样式风格!!Flex提供的几种主题(可以在Flex builder的帮助中以"theme"关键字搜到)文件类型都以".swc"为扩展名!!
其实就是将CSS打成一个swc库包,打包方法有很多,可以使用Flex提供的命令行工具(compc命令,可参看以"theme"为关键字搜到的Flex Builder帮助内容),
也可以使用Flex Library项目对src中的内容打包成swc包进而导出!!
*主题文件的使用:
**方法一: 在运行应用程序的时候传入附加参数"-theme xxx.css" ; 或者,修改项目的属性,
在"Flex Compiler"中的"additional compiler arguments"处的结尾添加"-theme xxx.css"参数。
**方法二: 修改Flex-config.xml(在Flex安装目录的sdks/3.2.0/frameworks目录中可找到)中的<theme>标签,来达到修改设置主题的效果!!
例如:
<theme>
<!-- 注意此时的CSS文件不是项目中的,而是Flex Builder中提供的,路径注意一下就可以了!! -->
<filename>themes/Smoke/Smoke.css</filename>
</theme>
*说明: 可以到Flex Builder的安装目录的sdks/3.2.0/frameworks/themes目录中拷贝Flex提供的几种主题,默认Flex使用的是"HelloClassic"主题。
注意: 文章中提到的《Flex3 Component Explorer》文档可到本人的下载空间中下载获得!