随笔-31  评论-257  文章-0  trackbacks-0
  2008年7月29日
最近由於種種緣故又要開始做點教育訓練的事,先趁現在有空把手邊的資料整理一下。

*Flex 的基礎架構

關於 flex 基本上常被問到的不外乎就是「如何可以學好它?」,要瞭解這個問題的答案基本上只要看懂下面這圖就ok了。



*Actionscript 該學的重點

從最底層看起,最下面的 actionscript 3是一切的基礎,它是 flash/flex 編程使用的唯一程式語言,因此任何人想學好 flex 第一件事絕對是先摸熟 actionscript 這個語言,包含:

1. 它的基本語法與結構(array, hash, loop, if else…)

2. DisplayList (DisplayObject, DisplayObjectContainer)與 Event system(bubbling, propagating…)

3. Sound, Video, NetConnection 與 Graphics class

掌握 as3 的精華後,接下來就可以進入 flex framework。

*Flex framework 的重點

基本上 flex framework 就是用 actionscript 寫成的框架,因此也可以把它看成是 as3的最好示範,看著 framework source 學 actionscript 也是挺不錯的,只是路會變很長。

Flex Framework 整個體系非常博大精深,通常一般人不太可能完整把它學完,只需要針對最常用到的部份熟悉就好,圖中列出的那三塊(component, managers, style/skin)就是我個人認為所有初學者最優先該學會的。

*Component 該學些什麼

Component 是整個 flex framework 的基礎,幾乎80% 的元素都是由 UIComponent 繼承而來,例如最根本的的 它本身就是一個 UIComponent,因此,熟悉 component 就成為學好 flex framework 最根本也最重要的基本功

Flex 內建了 二十幾個 UI controls, 例如 Button, DataGrid, HBox等,以種類來分,這些 components 可以概分為三大類:

-Controls: Button, DateChooser, Slider…
-Containers: Box, DividedBox, Panel…
-List: DataGrid, Tree, TileList…

初學者第一步至少該學會怎麼用這些元件,瞭解每個元件的 properties, events, styles, effects…,知道怎麼在手冊裏查它的 API 文件,以及何時該用何種元件。

進階一點,則是學會怎麼修改這些元件,例如繼承一個 Button 下來加上不同的功能,或是寫不同的 skin border 來改變它的外觀。

再更進階,則是開始研究元件的生命週期,瞭解每個元件是何時初始化,元件內部有那些關鍵指令與它們個別的功用,然後可以試著建立自已的 custom component。

這一關看起來容易但實際上最困難,因為 flex 的 component framework 寫的非常龐大,雖然亂中有序但要在混沌中看出隱藏的架構然後抓住重點整串提起,就非得有人帶著指引正確的途徑才比較可能達成。

*manager 是什麼

圖中最上方的第二塊就是 manager。

flex 裏有很多的 managers,負責做各種不同的工作(廢話…),幾個比較重要的包含:

-SystemManager:
它是每支 flex app 的根源,最先被下載,也最早啟動,由它進行一連串的 app boot流程

-StyleManager:
它負責整支app 的 css style 套用與 skin 生成,如果想玩動態 css 載換也靠它

-DragManager:
Flex最大的賣點就是 drag and drop,這個 manager 就是背後的英雄,初學者至少要學會怎麼處理 drag 行為的五個事件,以及如何在不同元件間做拖放;進階的玩家則應該深入研究這支 manager 是怎麼寫成的,詳細閱讀它的 source 會得到意想不到的無窮樂趣(如果你讀完卻沒有這種感覺,呃,那代表你該再多讀幾次,如果還是沒有,那請私下聯絡我 :D)

-ModuleManager:
使用 Flex 開發大型應用程式時,往往會將程式切割成許多小的 module, 這個 manager 就是負責載入並管理所有的 module (包含它的 class partition),初心者或許用不到,但有志深入的玩家一定要很熟。

-CursorManager:
這個用到的時機不是很多,但偶爾要換一下 cursor 時還是會用到,初學者至少要知道怎麼用指定的圖案去換掉系統cursor。

*Style/Skin 的重點

CSS style 與 skinning 是 Flex 最大的賣點之一,也是開發過程中較為麻煩也最耗時的部份。

初學者應該要徹底瞭解如何使用 CSS style 來打點一支 flex app 的外觀,換顏色、素材,使用外部 assets 修飾介面。

中階玩家則應該瞭解 skinning 的系統,包含 programmatic skinning 與 graphical skin,它們兩的差別?使用時機?如何客製化?

更高階的玩家則應該熟悉整個 Styling system 的運作模式,外加如何動態載入 css 在 runtime 換掉整個介面。

簡而言之,flex app 寫的好不好,外行人其實看不太出來,但一支 app UI 美不美則是一翻兩瞪眼,比較漂亮的那就先加十分

(當然,有一種情況是刻意用心去美化了介面結果弄巧成拙搞的怨聲載道人人喊打,但那種比較不多見,也不是每家公司都會搞到這步田地,就先不討論)

*學完基本功後下一步

在我的標準裏,當一個 developer 對上圖內每一塊都有中等程度的瞭解後,就算是完成 flex 養成教育,可以邁向下一個階段。

也就是開始熟悉 application 的製作手法,這包含

-瞭解至少一種以上的開發框架,例如 Cairngorm,老實說我對這個框架沒什麼好感(因為手法太複雜,只適合超複雜登月計畫或火星探勘時使用),但它結構設計良好,又是業界公認的聖盃,等於是專家們共通的語言,因此至少要先瞭解它在做什麼,將來在專業場合才好溝通(俗話說 know the rules so you know what you are breaking, 就是指這情況)

-接著可以看看比較簡單的手法,像 Riawave, Model-Glue:Flex, PureMVC…等,基本上這些框架設計方式都大同小異,每個都有不同的應用場合,可以挑一個喜歡的再自行修改。

-瞭解基本的概念,例如 Value Object, DAO, MVC 等,它們在大部份的程式框架裏都會出現,早點學會日子比較輕鬆。

接著就是開始實際 coding,寫一個中小型規模的app,不論是單純的 CRUD app,或是留言版、電話簿、進銷存管理都可以,籍由多寫來強化編程的概念,然後透過大量的 peer code review 來找出可改進的地方。

*結論

結論還是老話一句:要入門 flex 超級簡單,只要不是白癡應該一小時就行,但要成為可獨當一面的專業開發者,路就很長,如果沒有走對方向很容易就迷失甚至最後放棄。

換句話說,要能成為職場上真正需要的 professional developer,並不如表面上想像的容易(其實我想每種技術領域跟產業都一樣吧),這也是我過去半年來協助很多公司做 recruiting 後的感想。

posted @ 2008-07-29 14:46 姜大叔 阅读(1284) | 评论 (0)编辑 收藏
     摘要:       做Flex做久了做大了,就会觉得之前写的的Flex代码开始有点乱,哪怕你写的规范了,但总觉得结构松散,维护不方便,相信很多人刚开始做Flex的时候,都是想到什么功能,就写什么功能,或者有些好点的,就先画了个大体的流程图之类的,因为现在Flex普及得还不够,很多人做Flex也是试探阶段,不敢用作商业项目或其它大项目,只会用来试水技术层面的...  阅读全文
posted @ 2008-07-29 14:44 姜大叔 阅读(4960) | 评论 (32)编辑 收藏
      在上一篇文章中,为大家介绍了Flex中皮肤的简单且基本也是最常用的用法,就是先在外部程序中做好皮肤样式,之后再在Flex中加载这些皮肤资源,比如是PNG图片,或者是SWF文件等,这些方法都是比较直接且方便简单的。不过灵活性还是不太好,而现在这篇文章中要讲的,就是从程序里AS编写的皮肤,你可以更灵活自由地控制皮肤的样式与表达方式等,而不用依赖于外部的图片或SWF资源,不过这样还是有些缺点的,就是扩展或是改变时就比较不灵活,像图片资源的皮肤的话,可以很轻易的改变不同的图片的路径资源等就可以修改了不同的皮肤模式,而用AS Graphics写的皮肤的话,要修改一下那些代码,当然,你也可以在AS代码里写上动态加载其它图片资源又或者作一些更高级的效果等等。

      先在这里解析一下,要以代码方式自定义一个皮肤的话,需要自已编写一个皮肤子类,继承ProgrammaticSkin这个类,这个是所有编写自定义皮肤的基类,该类也派生了另外两个类:RectangularBorder 与 Border 类,都是差不多的,如果你是写Icon之类的小皮肤的话,比如CheckBox或者RadioButton这类皮肤不需要太复杂的画图逻辑,而且大小固定,就像是一个小Icon吧,只是有几个状态而已,这类小皮肤的话,继承ProgrammaticSkin就可以了,而写一些复合的控件,背景大小可以调节之类的皮肤(其实就是大部分皮肤)就用Border或者RectangularBorder类。但都有一个相同点,就是继承了那些类之后,都必需覆盖 updateDisplayList 这个方法,这个方法是由程序自动调用,当需要用到控件时,需要控件的皮肤进行表现时,就会调用那个方法,所以你必需覆盖它,并将你的画图逻辑代码写在那个方法里面。还有要注意的是,这个皮肤类会与你应用这皮肤的控件的Style设置共享,也就是说你可以在编写这个皮肤类代码里面,使用getStyle()等等方法获得设置在目标控件中的风格属性,比如说是<mx:Panel backgroundColor="0xffffff" borderSkin="MySkin"> 那么你可以在MySkin代码里获取这个颜色值来进行画出该颜色的图片或其它操作,而直接将颜色值写死在代码里是不规范的,就如我下面贴出来的的代码,不过出于自已懒,快速代个示例代码,所以犯这个错了。说多了,下面看看代码先。

好了,我们先看看看代码,这份代码是写了一个Panel的皮肤:
 1 package com.jiangzone
 2 {
 3     import mx.skins.Border
 4     import mx.core.EdgeMetrics;
 5     import mx.core.Container;
 6     import mx.graphics.RectangularDropShadow;
 7    
 8     public class MyPanelBorderSkin extends Border {
 9        
10         public function MyPanelBorderSkin():void {
11         }
12        
13         /**
14          * 该方法必需要覆盖,如果你要自定义自已的皮肤的话,
15          * 该方法当在控件更新外观时将会被自动调用
16          * 会传入两个参数数,第一个是Width,第二个是Height,即是该控件的宽与高
17          * */
18         override protected function updateDisplayList(w:Number,h:Number):void {
19             super.updateDisplayList(w,h);
20            
21             var ba:uint = 1;                //backgroundAlpha    背景透明度
22             var bg:uint = 0xffffff;            //backgroundColor    背景颜色
23             graphics.clear();                //graphics这个属性是父类里已经提供了的
24             var p:Container = parent as Container;        //获取该皮肤所应用在的父容器,这里为Panel
25            
26             //这里需要注意,一定要判断父容器是否已被设置,在文章里作解释
27             if(p){
28                 //获取容器定义的区域边界信息对象           
29                 var vm:EdgeMetrics = p.viewMetrics;       
30                 //设置四个角的圆度
31                 var radiusContent:Object = {tl:vm.top,tr:0,bl:0,br:vm.top};   
32                 //标题栏圆度   
33                 var radiusTitle:Object = {tl:vm.top,tr:0,bl:0,br:0};       
34                 //画一个圆角矩形,整个背景
35                 this.drawRoundRect(0,0,w,h,radiusContent,bg,ba);
36                 //画一个圆角矩形,标题栏   
37                 this.drawRoundRect(0,0,w,vm.top,radiusTitle,0xff0000,.7);
38                 //画一个圆角矩形,标题栏的那个高光水晶条
39                 this.drawRoundRect(0,0,w,vm.top / 2,radiusTitle,0xffffff,.3);
40                
41                 //下面是画阴影的。
42                 var dropShadow:RectangularDropShadow = new RectangularDropShadow();
43                 dropShadow.distance = 8;
44                 dropShadow.angle = 60;
45                 dropShadow.color = 0x000000;
46                 dropShadow.alpha = 0.4;
47        
48                 dropShadow.tlRadius = radiusContent.tl;
49                 dropShadow.trRadius = radiusContent.tr;
50                 dropShadow.blRadius = radiusContent.bl;
51                 dropShadow.brRadius = radiusContent.br;
52        
53                 dropShadow.drawShadow(graphics, 00, w, h);
54             }
55         }
56     }
57 }


上面的代码就是皮肤的代码,之后你还要做的,就是将该皮肤应用到Panel这个容器里:
 1 <mx:Application
 2     xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()"
 3     layout="absolute">
 4 
 5     <mx:Style>
 6         .myPanelSkin {
 7             borderSkin: ClassReference( "com.jiangzone.MyPanelBorderSkin" );
 8         }
 9     </mx:Style>
10    
11     <mx:Panel borderSkin="com.jiangzone.MyPanelBorderSkin"
12               width="200" height="150"  x="24" y="23"/>
13    
14 </mx:Application>


      代码很简单,这里要说一下,viewMetrics 这个属性是Container控件所独有的属性,是一个只读属性,编写Container子类的时候都要覆盖它,是用于定义这个容器正文区与边界值的,比如Canvas的四周都是0,所以没有标题栏与边条,而Panel就有四周的边界,而Top边界比较大,用作显示title的,所以如果你要做容器的皮肤的话,注意一下这个值。还有就是,为什么获取了皮肤应用的控件引用(parent)后还要判断它是否为空?因为当程序加载到这个控件时,是先加载那个皮肤的,所以parent的值未被设置,是空的,如果你不作判断的话,将会出现空引用的错误(parent.viewMetrics),当加载完皮肤后,再加载控件并设置控件的属性和设置皮肤,这时将会再次调用updateDisplayList的方法,这时parent才有值,就是那个控件的引用。当改变了style或一些属性后,又会自动触发调用updateDisplayList方法。

我们来看看最终运行效果:



补充一下:
在第一篇文章里,说了将皮肤做在SWF文件里再加载,想一下,可以将该皮肤做成动画MC的,而不单单只是一个画面,可以做成一些动画作为皮肤,之后在Flex引用该SWF的Symbol,这样皮肤就有了动画效果了,不只只是单纯的不动的平面图!

      Flex中的皮肤教程就说到这里,皮肤还有很多可探索的,只要大家有求知欲,多点看看英文文档,看看别人的例子程序代码,现在Flex也开源了,也可以多看看Flex的源码,会得到很多知识!



posted @ 2008-07-29 14:40 姜大叔 阅读(2415) | 评论 (2)编辑 收藏
      好久没有写文章了,一直用“忙”来为自已找籍口,其实是懒,不过这个月发生了这么大的事情 5.12 让我们每个人都永记心中,看到中国人的团结,看见解放军们志愿者们这么努力地为灾区奉献,我也不能再为自已找借口了,虽然我远在广东,不能到现场去参与救缓,钱也捐过了,但想想,我还有事情可以做的,就是用我自已的知识,写点技术文章,虽则不能直接的帮助到灾区,但也为国民提高Flex技术知识出分力,做好本职工作。在这里哆嗦点也得说句:为灾区遇难者祈祷,为灾区救缓不懈努力的军民给与崇高的敬意!
.....................................................(三分钟后)

      好了,我们转入正题,之前我也写过Flex的动画与变换的文章,不知道大家有没有看过。现在我要写的就是Flex中的皮肤样式方面的,我技术不太好,算是自已学习Flex过程中的理解体会吧。
      这里是第一篇,将讲述一下Flex中如何应用UI的皮肤,其实应用UI皮肤不难,你们在使用Flex的过程中是否觉得Flex中自带的皮肤样式不太好看?或者是想自已做个比较有特色的?下面就我们来说说皮肤吧,先来个简单的,你们在做网页时,做导航按钮什么的很多人都是用一个图片来作为一个按钮吧?之后做几个不同的颜色,之后就在CSS或者JS里设置一下当鼠标Over和Down和Out等等动作时,就切换不同颜色的图片,这样实现动态效果。在Flex里也可以如此简单的做皮肤。你可以先画好一个UI的皮肤,之就就将该图片应用到Flex里面。
先来看看效果:


之后我们来看看代码:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()" width="257" height="182" backgroundGradientColors="[#ffffff, #ffffff]">
 3    
 4     <mx:Script>
 5         <![CDATA[
 6            
 7             //Embed标签是用于将一些外部资源加入到Flex中,随Flex的编译成SWF文件,
 8             //这里是加入一张PNG图片,即是做好的Skin图片
 9             [Embed(source="images/buttonskin.png",
10                    scaleGridTop="26",
11                    scaleGridBottom="64",
12                    scaleGridLeft="30",
13                    scaleGridRight="106")]
14             //上面的Embed标签下面要紧跟着这个Class,意思就是将上面的资源加入到Flex
15             //后变为这个Class的内容,即调用这个Class时,就是调用那些资源
16             private var MyBtnSkin:Class;
17            
18             //在程序创建完成时会调用该函数,在函数里面设置Button的样式(Style)
19             //这里就是设置按钮的up,over,down三个鼠标状态时的皮肤,就是上面加入的图片资源
20             private function init():void{
21                 btn.setStyle("upSkin",MyBtnSkin);
22                 btn.setStyle("overSkin",MyBtnSkin);
23                 btn.setStyle("downSkin",MyBtnSkin);
24             }
25         ]]>
26     </mx:Script>
27     <mx:Button id="btn" label="Hello World" width="190" height="90"/>
28 </mx:Application>


      怎么样?很简单吧?大家需要注意一下的是在Embed标签里,我定义了一些scaleGridTop之类的属性,这是跟皮肤的缩放有关的,如果不定义那些属性的话,那么图片是多大的,就按多大来进行缩放,当你的按钮很大时,那些皮肤图片就会被拉大,出现马赛克与变形等,这都是不好看的。加入了9格缩放模式后,当你缩放按钮时,九个格中的四个角的区域不会被缩放,保持原样,中间格会宽高同时缩放,中间上下格会仅是宽度缩放,中间左右格只会高度缩放,这样,那个皮肤的边框无论你如何缩放,都是原来的大小比例,而不会将整个图片一起拉申。
      现在的按钮太单调了,只有一个外观,现在大家可以再加多两个不同颜色或者其它图案的图片作为不同状态的皮肤就可以了,比如将overSkin改成红色边框的图片等。

      其实大家有没有发现,上面代码的写法感觉比较麻烦的。我们可以用CSS来实现,我们可以直接点,将皮肤直接写在Button上,如下:
1 <mx:Button label="Hello World"
2         upSkin="@Embed('images/buttonskin.png')"
3         overSkin="@Embed('images/buttonskin.png')"
4         downSkin="@Embed('images/buttonskin.png')"
5     />

这样也是同样的效果。省事好多了吧。或者我们用CSS来写:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="257" height="182" backgroundGradientColors="[#ffffff, #ffffff]">
 3     <mx:Style>
 4         Button{
 5             up-skin:Embed(source="images/buttonskin.png",
 6                           scaleGridTop="26",
 7                           scaleGridBottom="64",
 8                           scaleGridLeft="30",
 9                           scaleGridRight="106");
10             over-skin:Embed(source="images/buttonskin.png",
11                           scaleGridTop="26",
12                           scaleGridBottom="64",
13                           scaleGridLeft="30",
14                           scaleGridRight="106");
15         }
16     </mx:Style>
17     <mx:Button id="btn" label="Hello World" width="190" height="90"/>
18 </mx:Application>

如果觉得加上CSS代码会令程序代码混乱的话,就将CSS代码写在CSS文件里去,在程序里导入CSS文件就可以了。(至于CSS的用法,我就不说了,反正Flex里的CSS方式与Html里的用法用样。只是要注意一下CSS里面设置的属性的名字就可以了)

<mx:Style source="styles/styles.css" />

      但有人可能会问,这样做的话,如果一个程序有很多不同的UI,并有不同的皮肤,那不就是要生成很多的图片?这个问得好,确实,如果以这种方式的话,就像一个网站里的images文件夹一样,有很多的小图片,这样太麻烦了,而且也不好维护。既然有这样的问题,我们就将皮肤干脆做成在一个文件里面算了,方便快捷,维护又方便,而这个文件,就是SWF文件。我们如果有Flash基础的话,基本对MC都不会陌生,对,这次我们的主角就是SWF里面的MC,我们可以将一个皮肤做成一个MC,在Flash里将所有用到的皮肤都做在一个SWF里,一个图片就像是一个MC,之后发布该SWF文件,在Flex里加载这个SWF文件,再在需要的皮肤里调用SWF里面相应皮肤的MC的名字就可以了。如下:
这个是在Flash里做好的皮肤SWF文件,里面有三个不同颜色的皮肤模式
[swf]attachments/month_0805/p2008518233635.swf[/swf]
这里要注意一下,在Flash里做这些皮肤时,要将MC加上链接,链接的名称,就是你在Flex里调用该皮肤的名称,图片如下:




在做好皮肤的SWF后,让我们回到Flex 里面,在Flex里写如下代码:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="257" height="182" backgroundGradientColors="[#ffffff, #ffffff]">
 3     <mx:Style>
 4         Button{
 5             up-skin:Embed(source="images/btnSkin.swf",symbol="btnUP");
 6             over-skin:Embed(source="images/btnSkin.swf",symbol="btnOVER");
 7             down-skin:Embed(source="images/btnSkin.swf",symbol="btnDOWN");
 8         }
 9     </mx:Style>
10     <mx:Button id="btn" label="Hello World" width="100" height="60"/>
11 </mx:Application>


注意一下的就是,在Embed标签里,要导入的资源文件不是PNG了,而是一个SWF,就是我们刚才在Flash里做好的皮肤文件,注意看,后面还跟着一个symbol属性,该属性就是指明你要调用哪一个MC,就是SWF里面的MC,记得,都要为每个MC做链接,并链接名字要与symbol里的名字致。至此,我们的皮肤就完成了。一个SWF文件就搞掂。这里是最终效果:


好了,这篇教程就到些结束,上面介绍的都是Skin的比较简单快捷的用法,不过灵活性就不是很大,但也是皮肤技术的最基础的,大家也可以再扩展一下其它用法等等的,在下篇文章,也就是Flex皮肤系列文章的(二)中,我会介绍一下用程序代码来编写皮肤,这就是不依赖于外部的资源文件,直接用AS3代码用Graphics来自已画皮肤。下篇将会用到AS3的Draw API方面的知识,请大家做好准备。

在此再次向我们的灾区战士们给与崇高的敬意!
posted @ 2008-07-29 14:37 姜大叔 阅读(7253) | 评论 (5)编辑 收藏
     摘要:       好久没有发表文章了,这天写了一个Flash的一个动画菜单的效果,在之前看到一个站的一个菜单效果挺不错,就试着自已也用纯AS3写一个出来试试。看了一下研究了一个算法,自已也写了个出来,写得比较粗糙,所以运行时可能还会有点小问题,有空要再优化一下算法才行。 有点像 Apple 的菜单效果。原本是计划用图片的,不过后...  阅读全文
posted @ 2008-07-29 14:33 姜大叔 阅读(1364) | 评论 (0)编辑 收藏
用PV3D做的一个Flex效果,有时间会整理一下代码与文档贴出来!
以下是效果:
posted @ 2008-07-29 14:31 姜大叔 阅读(12028) | 评论 (133)编辑 收藏
这篇文章是Flex动画效果变换的最后一编了,这篇将会讲述Flex中的“变面”(我自已的理解)技术,即是Transitions!

如果看过Flex SDK里面的自带的例子程序,有一个叫“Flex Store”的应用,在里面的手机列表中看某一个手机的详细时,就是这种效果,不多说,这篇会比较简单,先看看效果:


看到了效果了吧,这种的变换不难实现,再来看看代码再解析:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="695" height="555">
 3 <mx:states>
 4 <mx:State name="A">
 5     <mx:SetProperty target="{windowA}" name="width" value="500"/>
 6     <mx:SetProperty target="{windowA}" name="height" value="300"/>
 7     <mx:SetProperty target="{windowC}" name="width" value="150"/>
 8     <mx:SetProperty target="{windowC}" name="height" value="150"/>
 9     <mx:SetProperty target="{windowC}" name="y" value="333"/>
10     <mx:SetProperty target="{windowD}" name="x" value="373"/>
11     <mx:SetProperty target="{windowD}" name="width" value="150"/>
12     <mx:SetProperty target="{windowD}" name="height" value="150"/>
13     <mx:SetProperty target="{windowD}" name="y" value="333"/>
14     <mx:SetProperty target="{windowB}" name="x" value="23"/>
15     <mx:SetProperty target="{windowB}" name="y" value="333"/>
16     <mx:SetProperty target="{windowB}" name="width" value="150"/>
17     <mx:SetProperty target="{windowB}" name="height" value="150"/>
18     <mx:SetProperty target="{windowC}" name="x" value="200"/>
19 </mx:State>
20 <mx:State name="B">
21     <mx:SetProperty target="{windowD}" name="width" value="150"/>
22     <mx:SetProperty target="{windowD}" name="height" value="150"/>
23     <mx:SetProperty target="{windowC}" name="width" value="150"/>
24     <mx:SetProperty target="{windowC}" name="height" value="150"/>
25     <mx:SetProperty target="{windowA}" name="width" value="150"/>
26     <mx:SetProperty target="{windowA}" name="height" value="150"/>
27     <mx:SetProperty target="{windowB}" name="width" value="500"/>
28     <mx:SetProperty target="{windowB}" name="height" value="300"/>
29     <mx:SetProperty target="{windowA}" name="y" value="333"/>
30     <mx:SetProperty target="{windowC}" name="x" value="200"/>
31     <mx:SetProperty target="{windowC}" name="y" value="333"/>
32     <mx:SetProperty target="{windowB}" name="x" value="23"/>
33     <mx:SetProperty target="{windowD}" name="x" value="373"/>
34     <mx:SetProperty target="{windowD}" name="y" value="333"/>
35 </mx:State>
36 <mx:State name="C">
37     <mx:SetProperty target="{windowD}" name="width" value="150"/>
38     <mx:SetProperty target="{windowD}" name="height" value="150"/>
39     <mx:SetProperty target="{windowB}" name="width" value="150"/>
40     <mx:SetProperty target="{windowB}" name="height" value="150"/>
41     <mx:SetProperty target="{windowA}" name="width" value="150"/>
42     <mx:SetProperty target="{windowA}" name="height" value="150"/>
43     <mx:SetProperty target="{windowC}" name="width" value="500"/>
44     <mx:SetProperty target="{windowC}" name="height" value="300"/>
45     <mx:SetProperty target="{windowA}" name="y" value="333"/>
46     <mx:SetProperty target="{windowB}" name="x" value="200"/>
47     <mx:SetProperty target="{windowB}" name="y" value="333"/>
48     <mx:SetProperty target="{windowC}" name="x" value="23"/>
49     <mx:SetProperty target="{windowC}" name="y" value="19"/>
50     <mx:SetProperty target="{windowD}" name="x" value="373"/>
51     <mx:SetProperty target="{windowD}" name="y" value="333"/>
52 </mx:State>
53 <mx:State name="D">
54 <mx:SetProperty target="{windowC}" name="width" value="150"/>
55 <mx:SetProperty target="{windowC}" name="height" value="150"/>
56 <mx:SetProperty target="{windowB}" name="width" value="150"/>
57 <mx:SetProperty target="{windowB}" name="height" value="150"/>
58 <mx:SetProperty target="{windowA}" name="width" value="150"/>
59 <mx:SetProperty target="{windowA}" name="height" value="150"/>
60 <mx:SetProperty target="{windowD}" name="width" value="500"/>
61 <mx:SetProperty target="{windowD}" name="height" value="300"/>
62 <mx:SetProperty target="{windowA}" name="y" value="333"/>
63 <mx:SetProperty target="{windowB}" name="x" value="200"/>
64 <mx:SetProperty target="{windowB}" name="y" value="333"/>
65 <mx:SetProperty target="{windowD}" name="x" value="23"/>
66 <mx:SetProperty target="{windowD}" name="y" value="19"/>
67 <mx:SetProperty target="{windowC}" name="x" value="373"/>
68 <mx:SetProperty target="{windowC}" name="y" value="333"/>
69 </mx:State>
70 </mx:states>
71 <mx:transitions>
72 <mx:Transition fromState="*" toState="*">
73 <mx:Parallel targets="{[windowA, windowB, windowC, windowD]}">
74 <mx:Move />
75 <mx:Resize />
76 </mx:Parallel>
77 </mx:Transition>
78 </mx:transitions>
79 <mx:TitleWindow x="23" y="19" width="250" height="200" layout="absolute" title="A" id="windowA" click="currentState='A'" />
80 <mx:TitleWindow x="309" y="19" width="250" height="200" layout="absolute" title="B" id="windowB" click="currentState='B'" />
81 <mx:TitleWindow x="23" y="260" width="250" height="200" layout="absolute" title="C" id="windowC" click="currentState='C'" />
82 <mx:TitleWindow x="309" y="260" width="250" height="200" layout="absolute" title="D" id="windowD" click="currentState='D'" />
83 </mx:Application>


代码会比较多,我们先看看<mx:states>标签,它是一个集合,就是你的程序有多少个状态,什么是状态呢?我自已理解就即是有多少个“面谱”,即是现在程序里面有四个显示界面状态,所以里面有四个<mx:State>标签,每个<mx:State>状态都需要有一个名字name属性,以区分是哪个界面状态,在每个状态里面都有很多<mx:SetProperty>的标签,看英文都知道了,该标签用于设置这个状态下的所有界面元素的属性(组件的属性),因为每个界面状态中各个组件的大小布局都不同,所以在状态标签里就要预先设置好该状态下的组件的位置与大小,那个target="{windowC}"属性就是设置你要设置的哪个组件的名字拉,name="height"就是你要设置的属性value="333"就是你要设置该属性的值,我们细心看看的话,可能会发现,每个状态里面设置的属性,都是width,height,x,y这四个属性,我们看看上面的最终效果就知道无论切换哪个状态,组件间的变换来来去去都是移动位置与大小改变,就是说当你变换状态时,需要改动哪些属性的,就将它的目标值设置在<mx:SetProperty>标签里。再看看下面的<mx:transitions>标签,这个也是个集合,里面放着不同的变换方法<mx:Transition>,我们来看看变换标签的代码:
1 <mx:Transition fromState="*" toState="*">
2 <mx:Parallel targets="{[windowA, windowB, windowC, windowD]}">
3 <mx:Move />
4 <mx:Resize />
5 </mx:Parallel>
6 </mx:Transition>

formState与toState属性是要设置该状态变换是怎样触发的,里面要填上状态的名字,<mx:State name="C">   C就是状态的名字,即是如果你formState="A",toState="C"的话,只有从A状态切换到C状态时,才会产生以上的变换动画效果,如果不附合该规则如A切换到B状态的话,则只会按状态的属性设置值来直接生成视图,而没有动画渐变效果了。如果填上“*”的话,就是无论是哪个状态切换到哪个,都会运行动画效果,至于变换期间用到哪种动画效果来进行渐变,就在它的下级标签里定义了,这里它用到了<mx:Parallel>并列播放移动与重整大小的动画效果,之前文章讲过,这里不多说了。基本上,一个变换就做好了,但我们还需要触发它,也就是去改变程序当前的显示状态:click="currentState='A'" 在每个组件的click事件里,改变程序的currentState值,就是改变程序的当前显示状态!之后动画效果就会触发了!

迟点有时间,再做一个3D的动画效果,将会用到PV3D的框架,再整理一个代码与教程也贴出来跟大家分享吧,不过不知道大家对PV3D这个东东熟悉不,不熟悉的话,可能看得痛苦点,至于PV3D方面的教程,我也看看抽点时间写写吧!先谢过大家的支持!
posted @ 2008-07-29 14:28 姜大叔 阅读(6877) | 评论 (6)编辑 收藏
在上篇文章《Flex的动画效果与变换(一)》中讲到了使用Flex系统里面自带的一些动来效果的使用,但很多开发者都并不满足Flex里提供的简单的渐变大小,透明,移动,遮罩等的效果,如果是Flash的开发者的话,更不用说了,在Flash,多数人都是随意的制作一些动画效果等,而且形态多变。但是不是Flex里就不能实现呢?肯定不是,在Flex里也可以自定义动画效果,只不过就是没有Flash里面那么简单随意了。不过熟悉了之后,也会觉得在Flex里制作动画也不是什么难事,不多说了,转入正题!

在这里我先介绍一下Flex里面的动画效果机制,在Flex里面要使用动画效果的话,先要创建一个效果标签,之后在组件里(如TextInput)写上效果触发器,但可能会有人问,如果程序里我就只定义一个移动效果
<mx:Move>,之后我程序里面有5个组件,每个组件的动画效果都指向这个Move效果,那么它是不是组件一运行了效果后,组件二再触发效果,是不是组件一的效果会消失才会到组件二里播放?其它不是,虽然我们只定义了一个Move,但我们定义的只是Move效果的工厂,这里就用到了设计模式中的“工厂方法”模式,其实5个组件都可以同时运行效果,而5个效果都是不同的一个实例,彼此独立。所谓工厂方法模式,就好比是一家衣服制造工厂,A走进这家工厂说要一件衣服,工厂就制作一件合适A的Size的衣服,B进去,就会生产合适B的衣服,但A与B的衣服都是一样的。就好等于面向对象中的类与对象的关系一样。(我可能说多了-_-)
效果运行的时候,其实运行的不是Move这个对象,而是MoveInstance这个对象,Move只是工厂,既然一个动画效果就主要分这两大部份,我们就先建造一个工厂吧!

在Flex里面所有的效果的工厂都是继承自 mx.effects.Effect 这个类,我们也不能搞特殊,我们自定义的效果也要继承那个类,先看以下整个工厂类的代码:
 1 package com.jiangzone.flex.effects {
 2     import mx.effects.Effect;
 3     import mx.effects.EffectInstance;
 4    
 5     public class MyEffect extends Effect {
 6         private var _color:Number = 0xFF0000;
 7                
 8                 public function set color(value:Number):void {
 9                          _color = value;
10                 }
11 
12         public function MyEffect(newTarget:Object = null) {
13             super(newTarget);
14             instanceClass = MyEffectInstance;
15         }
16        
17         override public function getAffectedProperties( ):Array {
18             return [];
19         }
20        
21         override protected function initInstance(instance:EffectInstance):void {
22             super.initInstance(instance);
23                         MyEffectInstance(instance).color = _color;
24         }
25     }
26 }


大家看看上面的代码,其中先看构造函数,构造函数要接收一个默认为空的Object对象
public function MyEffect(newTarget:Object = null)
之后在该构造函数里面调用父类的构造函数,并且将instanceClass这个属性设置为你的该效果的实例类,因为这个类是工厂类,所以要知道你这个工厂生产什么产品,即上面说的“衣服”,所以这里我们将其命名为MyEffectInstance,注意:在Flex中的所有效果实例类都是在工厂类后面加Instance,也不是一定,只是规范而已。还有注意,下面一会定义的实例类的类名一定要跟这里的一致。
大家还会看到,上面的代码中,复写(override)了二个方法:getAffectedProperties( )与initInstance(instance:EffectInstance)
这两个方法都是要复写的,先说说getAffectedProperties( )这个方法,这个方法是获取被改变的属性值,怎么说呢,比如说,你做的动画效果如果要用到组件对象的一些属性的话,就要返回这些属性的名字,如:你的效果是对组件做旋转的话,则:
1 override public function getAffectedProperties( ):Array {
2     return ["rotation"];
3 }

反正你做的效果需要对组件修改什么属性的话,都在这个方法里返回名字,修改多个属性的话就往数组里加就是了。
后面就是这个方法了initInstance,该方法接收一个instance:EffectInstance参数,也就是效果实例类啦,因为每个效果实例类都要继承EffectInstance类,所以这个方法里的参数写的是父类,在里面要做其它的话,需要将 instance 转换为你相应的效果类。在这个方法里面,也是要调用父类的同名方法:super.initInstance(instance);
基本上,一个工厂类就写好了,但这样只是最简单的写法,试想想,每个人穿衣服的Size不同,喜欢的颜色也不同,所以,是不是可以由用户来定义他们想要的效果的颜色等属性呢?当然,你对衣服有什么要求,都是向工厂提出的,没有人会对衣服说吧?所以,这些可设置的属性也是定义在工厂类里面,所以下面,我们为该衣服可定制颜色为例,在工厂类里面加入如下代码:
1 private var _color:Number = 0xFF0000;
2 public function set color(value:Number):void {
3         _color = value;
4 }

你想运行时的效果可以设置不同的颜色的话,就可以直接设置MyEffect的color属性,之后将这个属性传给效果实例类:
1 override protected function initInstance(instance:EffectInstance):void {
2     super.initInstance(instance);
3         MyEffectInstance(instance).color = _color;
4 }

这些对效果实例类的设置,都是要定在initInstance方法里了,你想对运行时的效果设置什么属性的话,都要先告诉工厂类,之后工厂类在这个方法里面转嫁给实例类,这样,同一个效果,可以运行不同的颜色。但前提是你后面要写的实例类要有color这个属性。
现在已做好了工厂类了,下面要做效果实例类了,先贴出完整代码:
 1 package com.jiangzone.flex.effects {
 2     import mx.effects.EffectInstance;
 3     import flash.display.Shape;
 4     import flash.events.Event;
 5    
 6     public class MyEffectInstance extends EffectInstance {
 7                
 8         private var _color:Number;
 9         private var shape:Shape;
10        
11         public function set color(value:Number):void {
12             _color = value;
13         }
14        
15         public function MyEffectInstance(newTarget:Object) {
16             super(newTarget);
17         }
18        
19         override public function play( ):void {
20             super.play( );
21             drawShape();
22         }
23        
24         private function drawShape():void{
25             shape = new Shape();
26             shape.graphics.beginFill(_color);
27             shape.graphics.drawRect(target.width * -0.5,target.height * -0.5,target.width,target.height);
28             shape.graphics.endFill();
29             shape.x = target.x + target.width * 0.5;
30             shape.y = target.y + target.height * 0.5;
31             target.parent.rawChildren.addChild(shape);
32             target.addEventListener(Event.ENTER_FRAME,onEnterFrame);
33         }
34        
35         private function onEnterFrame(e:Event):void{
36             shape.scaleX += 0.1;
37             shape.scaleY += 0.1;
38             shape.alpha -= 0.05;
39             if(shape.alpha <= 0){
40                 target.parent.rawChildren.removeChild(shape);
41                 target.removeEventListener(Event.ENTER_FRAME,onEnterFrame);
42             }
43         }
44     }
45 }


我们看到,每一个动画效果实例类,都要继承自EffectInstance这个类,构造函数也是需要接收一个Object,这个Object其实就是你要应用到的组件对象,这个会是系统自动传递的,接收了Object后还要用该Object 调用父类的构造函数:super(newTarget);
之后还有一件必做的事,就是重写play()这个方法:override public function play( ):void
是不是对play()很熟悉?因为第一篇文章中,就用到这个方法来发动效果的播放的,所以,你需要做的动画编程都是在这个方法里。但还是要先调用父类的同名方法,super.play();之后的,就是你想怎么画就怎么画啦。我将画一个与要应用效果的组件一样大小的矩型,之后该矩形会放大并透明,效果都写在drawShape()方法里了。看到这个方法里面的代码,是不是跟Flash里的一样了?
这里再贴上MXML代码:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application layout="absolute" xmlns:mx="http://www.adobe.com/2006/mxml"
 3                                                         xmlns:pf="com.jiangzone.flex.effects.*">
 4         <pf:MyEffect id="myEffect" color="0xFFFFFF" />
 5         <mx:VBox x="100" y="43">
 6                 <mx:TextInput focusInEffect="{myEffect}" />
 7                 <mx:TextInput focusInEffect="{myEffect}" />
 8                 <mx:TextInput focusInEffect="{myEffect}" />
 9                 <mx:TextInput focusInEffect="{myEffect}" />
10         </mx:VBox>
11 </mx:Application>

这里先看看最终效果:


在这里,我用了ENTER_FRAME的写法,但是如果不用ENTER_FRAME方式制作动画的话,还有另外一种方法的,那就是Tween了,Tween是以“时间”为准,而ENTER_FRAME是以“帧”为准,其实到这里,一个基本的Flex自定义动画效果就完成了,但扩展一下的,还可以用Tween来实现,而且建议用Tween来写动画效果,易控制,清淅一点。用Tween实现的话,效果与写法都是差不多的,要用Tween就要将效果实例类继承自TweenEffectInstance这个类,并重写它的onTweenUpdate( )方法与onTweenEnd( )方法,这种Tween效果的写法,将会比ENTER_FRAME的写法方便,因为它根据的是时间,所以,你可以指定效果播放的时间,并且当播放完毕会自动调用onTweenEnd()方法,你可以在该方法里写一些处理操作,如释放资源等等
由于编幅关系,就不在这里详细介绍TweenEffectInstence了,就简单贴出该类的写法与注释吧:
 1 package com.jiangzone.flex.effects {
 2     import mx.effects.effectClasses.TweenEffectInstance;
 3     import flash.display.Shape;
 4     import flash.events.Event;
 5     import mx.effects.Tween;
 6    
 7     public class MyEffectInstance extends TweenEffectInstance {
 8                
 9         private var _color:Number;
10         private var shape:Shape;
11        
12         public function set color(value:Number):void {
13             _color = value;
14         }
15        
16         //构造函数
17         public function MyEffectInstance(newTarget:Object) {
18             super(newTarget);
19         }
20        
21         //同样的要重写play()方法与调用父类同名方法
22         override public function play( ):void {
23             super.play();
24             drawShape();        //先创建一个矩形
25             /*注意:用Tween效果写法的话,就一定要创建一个Tween对象
26             第一个参数是侦听器,即侦听Update与End的,这两个方法都在这个类里,
27             所以这里就写this,第二和第三个参数都是一个数组
28             第二个参数是初始值数组,第三个是结果值数组,都要一一对应,第四个是变化时间
29             这里的是[1,1]分别是初始时的scale比例与alpha,[3,0]就是最终结果数值
30             系统会自动在1000毫秒里平分这些值来得到渐变效果
31             并将每一次数值的改变时调用Update方法,结束后调用End方法
32                     你也可以将时间的参数发布到工厂类属性里,可以方便设置播放时间,像Flex自带效果一样
33                          */
34             new Tween(this,[1,1],[3,0],1000);
35         }
36        
37         override public function onTweenUpdate(value:Object):void{
38             //这里将改变的数值应用到组件对象中。注意:也要与上面的数值数组相对应。
39             shape.scaleX = Number(value[0]);
40             shape.scaleY = Number(value[0]);
41             shape.alpha = Number(value[1]);
42         }
43        
44         override public function onTweenEnd(value:Object):void {
45             //当播放完时会自动调用该方法,这里就做删除该矩形的操作吧
46             target.parent.rawChildren.removeChild(shape);
47         }
48        
49         private function drawShape():void{
50             shape = new Shape();
51             shape.graphics.beginFill(_color);
52             shape.graphics.drawRect(target.width * -0.5,target.height * -0.5,target.width,target.height);
53             shape.graphics.endFill();
54             shape.x = target.x + target.width * 0.5;
55             shape.y = target.y + target.height * 0.5;
56             target.parent.rawChildren.addChild(shape);
57         }
58     }
59 }


就写到这里吧,关于Tween其它的,就留作为作业,让大家思考与探索吧!之后如果有时间的话,将会写完下篇文章介绍Flex的“变面”动画,即状态变换!这里先谢谢大家支持!
posted @ 2008-07-29 14:24 姜大叔 阅读(5644) | 评论 (7)编辑 收藏
在Flex里面不像在Flash里面随意制作动画了,Flex更趋向于应用程序,而不是动画制作了,所以没有了时间轴的概念。在Flex中使用动画效果,可以用Flex自带的Effect,或者自已定制Effect,因为很多人都想借Flash里面的一样操作Flex,比如在Flash里面做一个动态按钮很容易,当鼠标移动到上面时,会有很多发光的点跑出来(荧火虫效果),这种效果在Flash十分容易实现,但在Flex里面要实现这种效果就不是那么简单的了,下面说说在Flex里的的动务效果的使用与自定义制作。

首先介绍一下Flex里面的自带的效果有以下几种:
  Blur                            模糊效果
  Move                          移动效果
  Fade                          淡入淡出效果            
  Glow                          发光效果
  Resize                       调整大小效果
  Rotate                       旋转效果
  Zoom                         缩放效果
  WipeLeft                    用遮罩实现画面收放效果,下同,分别为不同方向
  WipeRight
  WipeUp
  WipeDown

不同的效果所需要设置的属性也不一样,比如Blur效果需要设置它的X与Y轴的模糊像素
<mx:Blur id="blur" blurXFrom="0" blurXTo="10" />
而Move效果需要设置移动的位置信息
<mx:Move id="moveEffect" xFrom="-100" />
其它设置可以参考Flex语言参考

下面说说如何使用这些效果。要运行这些效果有两种方法:一种是调用该效果的play()方法,另外一种是使用触发器来触发效果。
(1)使用play()方法:
先看效果:

以下代码:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
 3     <mx:Script>
 4         <![CDATA[
 5             private function onClick(event:Event):void {
 6                 be.target = event.currentTarget;
 7                 be.play( );
 8             }
 9         ]]>
10     </mx:Script>
11    
12     <mx:Blur id="be" blurXTo="50" blurYTo="50" duration="1000" />
13 
14     <mx:Panel id="p" width="200" height="180" click="onClick(event)" />
15 </mx:Application>


在代码中看到,要使用效果,先定好一个效果,如上面的<mx:Blur ...>该标签就是模糊效果的MXML标签,定好效果后在Panel的点击事件里再对该效果进行一些设置,如be.target = event.currentTarget 设置该效果将要应用到的目标组件(Component),之后再调用play()方法后,该效果就会应用在Panel上面播放!

(2)使用触发器播放效果:
使用触发器播放效果的话,可以不用写ActionScript代码,直接在组件的效果触发器上指明使用哪个效果就可以了,比较简单明了,但就不能进行更多的属性定制,而用AS控制播放的话,可以对效果进行很多的设置再相应根据情况播放,先看看触发器播放的代码:
1 <?xml version="1.0" encoding="utf-8"?>
2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
3    
4     <mx:Blur id="be" blurXTo="50" blurYTo="50" duration="2000" />
5 
6     <mx:Panel id="p" width="200" height="180" creationCompleteEffect="{be}" />
7 </mx:Application>


看以上代码,先写好了Blur的效果并设置好属性后,duration="2000"这个是播放的时间以毫秒为单位。
在Panel标签里有这样一句:creationCompleteEffect="{be}" 这个就是触发器,是该Panel组件的效果触发器,当Panel组件加载完成时,会由系统自动调用该效果触发器,触发器里面指了触发 be 这个Blur效果
在Flex里面还有很多触发器如:
  addedEffect                                       被添加进容器时触发效果
  removedEffect                                   被从容器中移除时触发效果
  creationCompleteEffect                     被创建成功时触发效果
  focusInEffect                                     获得焦点时触发
  focusOutEffect                                   失去焦点时触发
  hideEffect                                          被隐藏时(visible=false)触发
  showEffect                                        被显示时(visible=true)触发
  rollOverEffect                                     鼠标经过时触发
  rollOutEffect                                       鼠标离开时触发
  mouseDownEffect                              鼠标按下时触发
  mouseUpEffect                                   鼠标松开时触发
  moveEffect                                         被移动时触发
  resizeEffect                                       被重整大小时触发

注意:这些都是效果触发器,不要与事件触发器混乱了。事件触发器是rollOver,事件触发器与效果触发器差不多,事件触发器是当用户执行相就操作时触发事件,将会调用自定的事件触发处理函数,而效果触发器是执行相应操作时被触发并由系统自动调用所定的效果的play()方法。

现在说说效果的一些其它属性:
每个效果都有reverse( );方法,该方法是反向播放,原本由小到大的变化,而调用reverse( );后再运行play()的话,效果将会从大到小进行播放。
但要注意的一点是,reverse( );不会自动播放,即是单单调用reverse( );的话,效果并不会播放,他只会记录该效果为倒转,而要再调用play()后倒转效果才会开始播放。而调用pause( )与resume( )就是暂停与继续播放效果

startDelay这个属性是设置效果的播放延时,以毫秒为单位,即要等待多少毫秒后效果才开始播放,如:
<mx:Blur id="be" blurXTo="50" startDelay="3000" />
该模糊效果将会在调用play()之后3秒才开始播放

repeatCount这个属性是设置效果的重复次数,默认为1,设置为0的话就是不停循环播放
<mx:Blur id="be" blurXTo="50" startDelay="3000" repeatCount="5" />

每个效果都有两个事件:effectStart 与 effectEnd
你可以在该效果事件的处理函数里面对效果作相应的操作,如:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
 3     <mx:Script>
 4         <![CDATA[
 5             import mx.events.EffectEvent;
 6             public function onEffEnd(e:EffectEvent):void{
 7                 e.effectInstance.reverse();
 8                 e.effectInstance.play();
 9             }
10         ]]>
11     </mx:Script>
12     <mx:Blur id="be" blurXTo="50" blurYTo="50" duration="2000" />
13 
14     <mx:Panel id="p" width="200" height="180" creationCompleteEffect="{be}" effectEnd="onEffEnd(event)" />
15 </mx:Application>

当效果播放完时,系统将会自动触发effectEnd事件,在处理函数里面,将该效果Instance即现时播放的效果实例进行倒转并播放,当播放完,又会触发effectEnd事伯,这样一直循环!

现在再来说说效果的组合:
通常如果你觉得只应用一个效果很单调的话,可以进行效果组合应用,即多个效果同时播放或者顺序播放,
如,当加载页面时,你想Panel先模糊到一定程度,再将Panel移动到某个位置,再把Panel还原成原来的清淅度(即消退模糊)。这样分析一下,一共用了三个效果,一,先应用Blur(由清至模)效果,当Blur完成时,再应用Move效果,当Move完成时,再应用另外一个Blur(由模至清)效果。这样三个效果组合就是按顺序组合,先后运行。先来看看效果:

再来看看代码:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
 3    
 4     <mx:Sequence id="sequenceEffect">
 5         <mx:Blur id="beOut" blurXTo="50" blurYTo="50" duration="500" />
 6         <mx:Move id="mv" xTo="200" yTo="150" duration="500" />
 7         <mx:Blur id="beIn" blurXFrom="50" blurYFrom="50" blurXTo="0" blurYTo="0" duration="500" />
 8     </mx:Sequence>
 9    
10     <mx:Panel id="p" width="200" height="180" mouseDownEffect="sequenceEffect"  />
11 </mx:Application>

看以上代码,<mx:Sequence id="sequenceEffect">标签就是顺序组合效果标签,当应用sequenceEffect效果的时候,它会按顺序播放该标签里面的三个子效果。

另外的就是同时播放了,
1 <mx:Parallel id="parallelEffect">
2           <mx:Blur id="beOut" blurXTo="50" blurYTo="50" duration="500" />
3       <mx:Move id="mv" xTo="200" yTo="150" duration="500" />
4 </mx:Parallel>

这个标签就是同时播放的效果标签,放在它里面的子效果都会同时播放,即一边模糊一边移动。这个都可以自由组合,<mx:Parallel>与<mx:Sequence>标签都可以自由组合,例如先按顺序先播放模糊,再同时播放移动与隐藏等。这里就不多说了。

使用Flex自带的效果基本用法就这些,下篇文章将讨论自定义效果的制作,下篇将会详细说说这篇文章上面说到的 effectInstance 即实例与工厂的概念。



posted @ 2008-07-29 14:20 姜大叔 阅读(20759) | 评论 (6)编辑 收藏
      近来在学习Flash的3D技术,现在我看过的就PV3D 与Away3D这两个开源框架,感觉还不错,好像Away3D的效果好点,但效率不如PV3D,PV3D算是亻为(不会用五笔打这个字-_-,我机子里又没拼音输入,将就下吧!)3D,不管这么多了,做个东西练练手,先看效果:



[url=http://www.jiangzone.com.cn/jiang/3dmusic/soundtest.swf]这里看看效果![/url]

    这个程序很简单到没无简单了,就只是用了PV3D框架中的Cube的3D对象,一口气生成64个放在数组里待用,之后用Flash里的声音类加载并播放声音,之后在ENTER_FRAME事件里检测当前声音的频谱,之后根据频谱的高低来调整Cube格子的高低,在Flash里获取的声音频谱有512个Float数据,代表512级频谱,而前256级为LeftChangle,后256级为RightChangle,由于如果生成256个3D对象的话,对CPU来说是个考验,所以就折中间隔抽取64个频段来显示,由于懒于写代码了,就只写了LeftChangle的频谱。

    以下是代码:
  1 //************导入需要用到的类
  2 import flash.display.Sprite;
  3 import org.papervision3d.scenes.Scene3D;
  4 import org.papervision3d.cameras.FreeCamera3D;
  5 import org.papervision3d.objects.Cube;
  6 import org.papervision3d.materials.MaterialsList;
  7 import org.papervision3d.materials.WireframeMaterial;
  8 import org.papervision3d.materials.ColorMaterial;
  9 import org.papervision3d.cameras.Camera3D;
 10 import     org.papervision3d.objects.Plane;
 11 
 12 //************定义需要用到的对象
 13 var cont:Sprite;
 14 var scene:Scene3D;
 15 var camera:FreeCamera3D;
 16 var ml:MaterialsList;
 17 var material:ColorMaterial;
 18 var cubeArr:Array;
 19 
 20 //***********设置放置3D东东的容器
 21 cont = new Sprite();
 22 cont.x = 150;
 23 cont.y = 120;
 24 this.addChild(cont);
 25 
 26 //******设置一个3D场景,并设置好Camera的位置与角度
 27 scene = new Scene3D(cont);
 28 camera = new FreeCamera3D();
 29 camera.z = 1200;
 30 camera.x = 100;
 31 camera.y = 700;
 32 camera.rotationX = -30;
 33 camera.rotationY = 180;
 34 camera.focus = 100;
 35 camera.zoom = 10;
 36 
 37 //***********定义一个存放所有格子的数组
 38 cubeArr = new Array();
 39 
 40 //定义一个颜色材质与材质列表,用于应用于格子的6个面的贴图
 41 material = new ColorMaterial(0x096288);
 42 ml = new MaterialsList();
 43 ml.addMaterial(material,"front");
 44 ml.addMaterial(material,"back");
 45 ml.addMaterial(material,"top");
 46 ml.addMaterial(material,"bottom");
 47 ml.addMaterial(material,"left");
 48 ml.addMaterial(material,"right");
 49 
 50 var i:int = 0;
 51 var j:int = 0;
 52 
 53 //生成64个小格子并排列好位置
 54 for(;i<64;i++){
 55     ml.addMaterial(new ColorMaterial(0xB9DFCF),"top");
 56     var c:Cube = new Cube(ml,20,20,20);
 57     c.x = (i % 8* (20 + 5);
 58     c.z = (j % 8* (20 + 5);
 59     (i % 8 == 0? j++:j=j;
 60     cubeArr[i] = c;
 61     scene.addChild(c);
 62 }
 63 
 64 //创建一个面板,设置好位置放在小格子队列的下面(地板)
 65 var plane:Plane = new Plane(new WireframeMaterial(0xaaaaaa),300,300,7,7);
 66 plane.rotationX = -90;
 67 plane.y = -50;
 68 plane.x = 70;
 69 plane.z = 60;
 70 scene.addChild(plane);
 71 
 72 //以上是3D部分,以下是声音部分
 73 //建立一个字节数组用于存放获取到的频谱信息
 74 var bArr:ByteArray = new ByteArray();
 75 //读取声音文件并播放
 76 var req:URLRequest = new URLRequest("a.mp3");
 77 var sound:Sound = new Sound(req);
 78 sound.play();
 79 
 80 //添加一个事件侦听器
 81 this.addEventListener(Event.ENTER_FRAME,onEnter);
 82 
 83 function onEnter(e:Event):void{
 84     //获取当前声音频谱,将数据存放在bArr里面。
 85     //true为频谱模式,0为采样率代号
 86     SoundMixer.computeSpectrum(bArr,true,0);
 87     i=0;
 88     //读取前256个数据,即Left声道的频谱
 89     for(;i<256;i++){
 90         var temp:Number = bArr.readFloat();
 91         //间隔4个数据中获取一个显示
 92         if(i % 4 == 0){
 93             //从数组中获取相应的格子
 94             var c:Cube = cubeArr[i/4] as Cube;
 95             //设置格子在三维坐标中的高。
 96             //由于频谱数据是0-1,所以将其放大100倍
 97             c.y = temp * 100;
 98         }
 99     }
100     //镜头旋转移动
101     camera.moveLeft(12);
102     camera.rotationY += 0.6;
103     scene.renderCamera(camera);
104 }



posted @ 2008-07-29 14:16 姜大叔 阅读(1431) | 评论 (1)编辑 收藏
仅列出标题  下一页