《Flex 第一步》
//什么是Flex
Flex 是一个针对企业级富互联网应用的表示层解决方案。具体地说,Flex是一种应用程序框架。
富互联网应用程序,Rich Internet Application,简称RIA,将桌面应用程序的强交互性和传统Web应用的灵活性结合,对比HTML,表现更花哨,更有趣,更有个性。
//Flex的特性
使用矢量图形;丰富的组件库;对多媒体的广泛支持;
与服务器端的通信:除了可以加载XML和其它文本资料外,Flex还可以和ASP、 ASP.NET、PHP、JSP等多种服务器端程序通信,连接远程WebService,同时Flex还支持Remoting和 Socket等高级数据通信方式。
//Flex和Flash
Flash 的重用性不好;Flex数据交互能力更突出
//Flex程序的组成
以 mxml为后缀的程序文件;以as为后缀的ActionScript文件;以css为后缀的样式表文件
//MXML文件结构
是一个标准的XML文件,包括了版本、编码(可选,默认为utf-8)、命名空间(xmlns)。在一个Flex项目中,可能有很多个MXML文件,但作为程序入口的运行文件只有一个,主文件的标识是根节点为mx:Application,一个程序中只能出现一个mx:Application节点。
//添加按钮事件
当为一个按钮添加click事件时,系统会自动提示生成EventHandler。注意要先定义按钮的ID。
//自定义MXML组件
新建 MXML组件,组件会出现在“组件”面板上,像使用Flex自带组件一样,将其拖放到主程序中即可。
//在MXML文件中插入 ActionScript块
通常情况下,将<mx:Script>标签放在紧跟根节点的位置,放在其他MXML代码的前面:
<mx:Application xmlns:...>
<mx:Script>
<![CDATA[
// 这里是ActionScript代码
]]>
</mx:Script>
</mx:Application>
//调试
F8是运行。F5单步跳入。F6单步跳过。Ctrl+F2终止。
//断点
断点右键可设置断点属性,定义断点的条件。
//生成get,set
高亮字段,如_NewsId,右键,源代码,生成Getter/Setter
//List(array)和 Tree(xml)的绑定
<mx:List x="20" y="20" dataProvider="{array_data}" width="180"></mx:List>
<mx:Tree x="20" y="200" labelField="@label" dataProvider="{myData}" width="180"></mx:Tree>
//常用布局组件
Canvas(自由布局)、VBox(垂直布局)、HBox(水平布局),默认状态下滚动条采用自动适应的原则。
Panel具有Canvas、VBox和HBox 的所有功能。如果Panel的layout属性值为“absolute”,则Panel对子级元素的布局方式和Canvas一样;当值为 horizontal时相当于HBox,值为vertical则相当于VBox。
TitleWindow组件继承于Panel组件,与Panel 相比,它只多了一个关闭按钮。关闭事件为close。
Grid可以像Table一样使用,单元格也有colSpan和rowSpan。
Accordion 组件:一个可折叠的导航器,它包含一个子面板的列表,一次仅显示一个面板,可切换。
ViewStack组件:由若干个重叠在一起的子容器组成,每次只有一个容器是可见或活动的。要通过AS代码来控制切换,设置viewstack.selectedChild。
TabNavigator,继承自ViewStack,类似ajax的tab控件。
//事件查看和生成
选中控件,点击菜单栏“窗口”“属性”,在属性窗口中,选择“按字母排序视图”。
//form表单控件
通过 FormItem快速部署了一个用户信息表单。对表单的验证:
<mx:StringValidator source="{user_txt}" property="text" minLength="6" maxLength="12" tooShortError="用户名太短了"/> //自定义提示取代默认提示
<mx:StringValidator source="{pass_txt}" property="text" minLength="6" maxLength="12"/> //默认提示
<mx:PhoneNumberValidator source="{phone_txt}" property="text"/> //电话验证
<mx:DateValidator source="{birth_txt}" property="text"/> //日期验证
<mx:EmailValidator source="{email_txt}" property="text"/> //email验证
//DataGrid组件
<mx:DataGrid ... dataProvider="{books.book}">...<mx:columns><mx:DataGridColumn dataField="name" headerText="书名"/>... //Model的id为books
在 DataGrid组件中使用itmeRenderer(加入自定义控件):...<mx:DataGridColumn headerText="购买" itemRenderer="view.cartCell"/>...
除了itemRenderer,同样可以自定义的还有headerRenderer和itemEditor,前者控制标题栏的界面,后者控制单元格在编辑状态下的界面(DataGrid的 editable为true时)
//Tree组件
<mx:Tree ... dataProvider="{files}" labelField="@label" change="treeChange(event)"... /> //XMLList的id为files;
public function treeChange(event:Event):void { selectedNode = Tree(event.target).selectedItem as XML; txt.text = selectedNode.@label; }
//TileList组件
和 List一样,它也支持自定义itmeRenderer。<mx:TileList itemRenderer="ImageItem" ... dataProvider="{images.item}"> //ImageItem是mxml自定义控件
//文件处理
Text、 TextInput和TextArea。Text可以支持html标签(即解释html),不过需要借助htmlText标签(使用时必须含有CDATA 标签)
RichTextEditor编辑器,使用obj.htmlText和obj.text得到文本值。
//导航类控件
ToggleButtonBar 和TabBar,dataProvider为Array。ViewStack的定义:
<mx:ViewStack id="myViewstack" ...>
<mx:Canvas id="child1" ...>...</mx:Canvas>
<mx:Canvas id="child2" ...>...</mx:Canvas>
<mx:Canvas id="child3" ...>...</mx:Canvas>
</mx:ViewStack>
//menuBar组件
以特定格式的xml对象作为数据提供者,如<node label="清除画板" data="clear" enabled="false"/>,使用MenuEvent.item.@data取得选择值。
//PopUpButton和 PopUpMenuButton
PopUpButton可以将任何组件作为窗口弹出,置于最上层。主要事件有 PopUpButtion.open()和PopUpButton.Close()。
PopUpMentButton是前者的一个特例,它只能把 Menu控件当作弹出窗口。Menu控件用来创建菜单,相比MenuBar,它缺少了菜单条,而且没有对应的MXML标签,只能由代码创建。
/*Flex事件机制*/
as3.0全部采用addEventListener方法来注册监听器,且监听器必须是函数,监听器的作用域和监听器所在对象的作用域一致。
EventDispatcher对象负责实现事件模型,它提供了三个关键的函数来运作事件机制:addEventListener、 removeEventListener和dispatchEvent(派发)。
DisplayObject作为一切可视化元素的父类,直接继承于EventDispatcher对象,也就是说,as3.0中所有可视化对象都具有派发事件的功能。
事件流运行流程分为三步:捕获事件、检测目标的监听器、事件冒泡。
默认情况下,捕获功能处理关闭状态。另外,事件只在bubbles属性为true时才进行冒泡,可以冒泡的事件包括:change、click、doubleClick、keyDown,keyUp、mouseDown、mouseUp。
不可以在一个监听器中同时打开捕获和冒泡功能。要做到这一点,只能注册两个监听器,一个打开捕获功能,一个打开冒泡功能,比如:
canvas1.addEventListener(MouseEvent.CLICK,pressBtn,true);
canvas1.addEventListener(MouseEvent.CLICK,pressBtn);
evt:MouseEvent,evt 对象的四个属性:target表示派发事件的目标对象,currentTarget表示事件流当前正经过的目标对象;bubbles表示是否打开了冒泡功能;eventPhase则表示事件流当前的阶段,1表示捕获,2表示检测,3表示冒泡。
addEventListener(type:String,listener:Function,useCapture:Boolean=false,priority:int=0,useWeakReference:Boolean=false)
//useCaptrue 表示是否打开捕获功能,默认为false;priority表示监听器优先级,默认为0;useWeakReference指定是否使用弱引用,默认为 false。
当综合使用MXML标签和AS来给同一个对象注册监听器时,很难确立这些监听器之间的前后顺序,即无法控制监听函数的执行顺序。如果事件的执行需要按照某一个顺序来进行时,可以使用 addEventListener方法的priority参数来实现(数字越大,级别越高),如:
btn.addEventListener(MouseEvent.CLICK,press1,false,1);
btn.addEventListener(MouseEvent.CLICK,press2,false,4);
btn.addEventListener(MouseEvent.CLICK,press3,false,2);
注意,给一个对象注册多个监听器,即使第个监听器的优先级别不同,但也无法保证后一个执行时前面的监听函数已经执行完毕。因此,在设计程序时,后面的函数不应该以前者执行完毕为条件,最好让各个监听器互相独立。
Flash Palyer的垃圾回收机制:
将已经不再使用的对象清除,释放所占的内存资源,提高程序的运行效率。它的运行有自己的规律,而且是周期性的,并不会在第一时间(比如你把一个对象设为null的时候)将系统中的垃圾资源清理,它通常是在系统资源匮乏的情况下才进行。
如果在对象注册监听器的时候(addEventListener时)默认使用了强引用,Flash Player为了保证程序的运行,会在内存中保留这个对象。即使把它设成null,也只是表面上被删除,实际还是留在内存中,成为一个“幽灵”。
要避免“幽灵”,在注册监听器时,应该养成使用弱引用的习惯,同时,要使用预先定义的函数作为监听函数,而不是临时定义的函数(var f:Function = function():void { ... })。
//拖曳事件(List控件为例)
List1.dragEnabled = true; //可拖
List1.dropEnabled = true; //可放
List1.dragMoveEnabled = true; //不出现重复数据,只调整元素位置
/*第6章 使用行为对象和动画效果*/
<mx:Move id="myMove" target="{img}" xFrom="50" xTo="150" duration="2000"/> //移动id为img的图片控件,从x坐标50到150,用时2秒
private function initUI():void{
Effect_Blur.targets = [myPanel]; //模糊对象id是myPanel
}
<mx:Blur id="Effect_Blur" effectEnd="endBlur()" blurXFrom="0" blurXTo="30" blurYFrom="0" blurYTo="30" duration="1500"/>
internal function endBlur():void{
if(handlerEnd){
isReverse = !isReverse; //反向变化
Effect_Blur.play(null,isReverse);
}
}
Effect_Blur.resume(); //继续
Effect_Blur.pause(); //暂停
Effect_Blur.end(); //停止
Effect_Blur.play(); //播放
private function initUI():void{ Effect_Glow.target = myPanel;} //发光对象
<mx:Glow id="Effect_Glow" alphaFrom="1.0" alphaTo="0.3" blurXFrom="0.0" blurXTo="30.0" blurYFrom="0.0" blurYTo="30.0" color="ox6633ff"/>
Effect_Glow.play(); //播放
myPanel.filters = []; //停止,将新的数据赋予对象,新的滤镜生效
var newResize:Resize = new Resize(); //缩放图片
newResize.heightFrom = 200; //设定高度和宽度的起始值
newResize.widthFrom = 200;
newResize.heightTo = 240; //高度的最终值
newResize.widthBy = 40; //宽度增加40相当于 widthTo = 240
newResize.hideChildrenTargets = [Panel_1,Panel_2]; //指定要隐藏内部元素的Panel,缩放时隐藏p1和p2
newResize.target = Canvas_1; //缩放对象
newResize.duration = 2000; //持续时间
newResize.addEventListener(TweenEvent.TWEEN_END,myEndHandlerFun); //监听动画的结束事件
/*第9章 数据绑定*/
//Canvas背景绑定取色器:
<mx:Style source="style.css"/> //引用样式文件
<mx:ColorPicker id="mColor" x="30" y="30"/> //取色器
<mx:Canvas styleName="box" id="box" x="30" y="80" backgroundColor="{ mColor.value.toString() }" width="200" height="160"></mx:Canvas>
//数据绑定
使用大括号是实现数据绑定的最快捷方式。只需要将源数据对象放在大括号中,作为目标对象的值就可以了。
<mx:TextInput id="name_txt" x="89" y="10" width="133"/>
<mx:Text x="89" y="115" text="{name_txt.text}" width="133"/> //以name_txt.text为数据源,即时更新
<mx:Script>
<![CDATA[
[Bindable] //标识数据源
internal function ShowAge(s:String):String{
var n:Number = Number(s);
if(n>=16) return "成年";
return "未成年";
}
]]>
</mx:Script>
<mx:Text x="89" y="150" text="{ShowAge(age_txt.text)}" width="133"/>
//使用<mx:Binding>
好处在于,可以将数据绑定和描述界面的MXML代码分离开来,使得程序结构井井有条。
<mx:Model id="users"> //数据源对象
<users><user><name>Peter Ent</name></user></users>
</mx:Model>
<mx:Label id="name_txt" x="10" y="135" width="154"/>
<mx:Binding source="users.user.name" destination="name_txt.text" /> //id.item.property
//绑定类对象
[Bindable]
public class myTest{
public var className:String = "";
}
<tree:myTest id="test"/> //使用MXML标签定义非可视化类对象,在initApp或在点击时为属性赋值
<mx:Label id="tip_txt" x="0" y="20" title="{test.className}"/>
如果组件是程序创建的(如上面的 test是new出来的),那就要用:
BindingUtils.bindProperty(tip_txt,"title",test,"className"); //将test的className和tip_txt的title属性绑定
BindingUtils.bindSetter(setName,test,"className"); //将test的className属性和setName函数绑在一起,setName参数是一个string,参数值是test的className
//派发事件
在类中,可以通过属性的setter派发,如在myTest类中:
[Bindable("NumChange")] //属性可绑定,定义了一个NumChange事件
public function set Num(n:Number):void{
if(num != n){
num = n;
this.dispatchEvent(new Event("NumChange")); //派发事件
}
}
在主程序里可以添加监听:
test = new myTest();
test.addEventListener("NumChange",handler); //当test的num被赋值时会触发handler函数
注意,数组类型的对象,其子元素是无法作为数据源参与绑定的。如不能期望一个文本控件绑定到array中某一个元素。
Object类实例不能实现绑定,因为Object类型属于动态类型,我们可以随意地向里面添加任何属性,而且属性的类型也是任意的,编译器很难正确识别这些属性和属性的数据类型。要解决这个问题,需要使用 mx.utils包中的ObjectProxy对象。
//定义绑定类
[Bindable]
public class people
{
public var name:String;
public var email:String;
public var img:String;
function people(obj:Object):void{ //构造函数
for(var i:String in obj){
this[i] = obj[i];
}
}
}
/*第10章 组件的使用*/
// 应用样式
//使用主题
//修改组件外观
//创建组件
/*第11章 Flex2.0新特性实例开发*/
//处理XML
//example one
private var myData:XML = <items>
<item type = "流行音乐"><song>每一刻都是崭新的</song></item>
<item type = "古典音乐"><song>拉德斯基进行曲 </song></item>
<item type="乡村音乐"><song>光阴的故事</song></item>
</items>;
internal function initApp():void{
source_txt.text = myData.toXMLString(); //字符串输出
output(" 节点数目:"+myData..item.length()); //myData.child("item").length(),输出3
for (var prop:String in myData..item){ //var prop:String in myData.child("item"),prop是节点的索引,0,1,2
var node:XML = myData..item[prop]; //myData.child("item")[prop]
output("节点:"+prop);
output("属性名:"+String(node.@type)); //node.attribute("type")
output(" 子节点:"+node.song); //node.child("song")
output("----------");
}
output(myData..item.(@type == "流行音乐")); //属性type
output(myData..item.(song != "光阴的故事").song); //节点song
//example two
var xml:XML = new XML("<items></items>"); //定义根
var node:XML = <item type = "流行音乐"><song>每一刻都是崭新的</song></item>;
xml.appendChild(node); //添加节点
node = <item type = "古典音乐"><song>拉德斯基进行曲 </song></item>;
xml.insertChildBefore(xml..item.(@type == "流行音乐"),node); //插入节点
var tmp:XML = node.copy(); //复制节点(含节点值)
tmp.@type = "乡村音乐"; //重新赋值(覆盖原值)
tmp.song = "光阴的故事";
xml.appendChild(tmp);
output(xml.toXMLString());
//example three
internal function initApp():void{
var loader:URLLoader = new URLLoader();
loader.load(new URLRequest("http://rss.sina.com.cn/news/allnews/sports.xml")); //返回请求的页面信息(源代码)
loader.addEventListener(Event.COMPLETE, completeHandler); //完成事件
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
CursorManager.setBusyCursor(); //鼠标等待
}
internal function completeHandler(evt:Event):void{
CursorManager.removeBusyCursor(); //移除等待
var myXML:XML = XML(evt.target.data); //类型转化
parseRSS(myXML); //输出
}
internal function parseRSS(xml:XML):void{
var items:ArrayCollection = new ArrayCollection(); //结果集
for(var i:String in xml..item){
var node:XML = xml..item[i]; //结点
var obj:Object = new Object(); //实体
obj.title = node.title;
obj.link = node.link
obj.pubDate = node.pubDate;
obj.description = node.description;
items.addItem(obj);
}
newsList.labelField = "title"; //显示字体
newsList.dataProvider = items;
}
internal function showNews():void{ //<mx:List id="newsList" width="100%" change="showNews()"></mx:List>
var item:Object = newsList.selectedItem;
news_txt.htmlText = "<b><a href='"+item.link+"'>"+item.title+"</a></b><br/>";
news_txt.htmlText += "发布日期:"+item.pubDate+"<br/><br/>";
news_txt.htmlText += item.description+"<br/>";
}
/*第11章 Flex2.0新特性实例开发*/
//正则表达式
//声音控制
//Socket通信