在上篇文章《Flex的動(dòng)畫(huà)效果與變換(一)》中講到了使用Flex系統(tǒng)里面自帶的一些動(dòng)來(lái)效果的使用,但很多開(kāi)發(fā)者都并不滿(mǎn)足Flex里提供的簡(jiǎn)單的漸變大小,透明,移動(dòng),遮罩等的效果,如果是Flash的開(kāi)發(fā)者的話,更不用說(shuō)了,在Flash,多數(shù)人都是隨意的制作一些動(dòng)畫(huà)效果等,而且形態(tài)多變。但是不是Flex里就不能實(shí)現(xiàn)呢?肯定不是,在Flex里也可以自定義動(dòng)畫(huà)效果,只不過(guò)就是沒(méi)有Flash里面那么簡(jiǎn)單隨意了。不過(guò)熟悉了之后,也會(huì)覺(jué)得在Flex里制作動(dòng)畫(huà)也不是什么難事,不多說(shuō)了,轉(zhuǎn)入正題!
在這里我先介紹一下Flex里面的動(dòng)畫(huà)效果機(jī)制,在Flex里面要使用動(dòng)畫(huà)效果的話,先要?jiǎng)?chuàng)建一個(gè)效果標(biāo)簽,之后在組件里(如TextInput)寫(xiě)上效果觸發(fā)器,但可能會(huì)有人問(wèn),如果程序里我就只定義一個(gè)移動(dòng)效果
<mx:Move>,之后我程序里面有5個(gè)組件,每個(gè)組件的動(dòng)畫(huà)效果都指向這個(gè)Move效果,那么它是不是組件一運(yùn)行了效果后,組件二再觸發(fā)效果,是不是組件一的效果會(huì)消失才會(huì)到組件二里播放?其它不是,雖然我們只定義了一個(gè)Move,但我們定義的只是Move效果的工廠,這里就用到了設(shè)計(jì)模式中的“工廠方法”模式,其實(shí)5個(gè)組件都可以同時(shí)運(yùn)行效果,而5個(gè)效果都是不同的一個(gè)實(shí)例,彼此獨(dú)立。所謂工廠方法模式,就好比是一家衣服制造工廠,A走進(jìn)這家工廠說(shuō)要一件衣服,工廠就制作一件合適A的Size的衣服,B進(jìn)去,就會(huì)生產(chǎn)合適B的衣服,但A與B的衣服都是一樣的。就好等于面向?qū)ο笾械念?lèi)與對(duì)象的關(guān)系一樣。(我可能說(shuō)多了-_-)
效果運(yùn)行的時(shí)候,其實(shí)運(yùn)行的不是Move這個(gè)對(duì)象,而是MoveInstance這個(gè)對(duì)象,Move只是工廠,既然一個(gè)動(dòng)畫(huà)效果就主要分這兩大部份,我們就先建造一個(gè)工廠吧!
在Flex里面所有的效果的工廠都是繼承自 mx.effects.Effect 這個(gè)類(lèi),我們也不能搞特殊,我們自定義的效果也要繼承那個(gè)類(lèi),先看以下整個(gè)工廠類(lèi)的代碼:
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 }
大家看看上面的代碼,其中先看構(gòu)造函數(shù),構(gòu)造函數(shù)要接收一個(gè)默認(rèn)為空的Object對(duì)象
public function MyEffect(newTarget:Object = null)
之后在該構(gòu)造函數(shù)里面調(diào)用父類(lèi)的構(gòu)造函數(shù),并且將instanceClass這個(gè)屬性設(shè)置為你的該效果的實(shí)例類(lèi),因?yàn)檫@個(gè)類(lèi)是工廠類(lèi),所以要知道你這個(gè)工廠生產(chǎn)什么產(chǎn)品,即上面說(shuō)的“衣服”,所以這里我們將其命名為MyEffectInstance,注意:在Flex中的所有效果實(shí)例類(lèi)都是在工廠類(lèi)后面加Instance,也不是一定,只是規(guī)范而已。還有注意,下面一會(huì)定義的實(shí)例類(lèi)的類(lèi)名一定要跟這里的一致。
大家還會(huì)看到,上面的代碼中,復(fù)寫(xiě)(override)了二個(gè)方法:getAffectedProperties( )與initInstance(instance:EffectInstance)
這兩個(gè)方法都是要復(fù)寫(xiě)的,先說(shuō)說(shuō)getAffectedProperties( )這個(gè)方法,這個(gè)方法是獲取被改變的屬性值,怎么說(shuō)呢,比如說(shuō),你做的動(dòng)畫(huà)效果如果要用到組件對(duì)象的一些屬性的話,就要返回這些屬性的名字,如:你的效果是對(duì)組件做旋轉(zhuǎn)的話,則:
1 override public function getAffectedProperties( ):Array {
2 return ["rotation"];
3 }
反正你做的效果需要對(duì)組件修改什么屬性的話,都在這個(gè)方法里返回名字,修改多個(gè)屬性的話就往數(shù)組里加就是了。
后面就是這個(gè)方法了initInstance,該方法接收一個(gè)instance:EffectInstance參數(shù),也就是效果實(shí)例類(lèi)啦,因?yàn)槊總€(gè)效果實(shí)例類(lèi)都要繼承EffectInstance類(lèi),所以這個(gè)方法里的參數(shù)寫(xiě)的是父類(lèi),在里面要做其它的話,需要將 instance 轉(zhuǎn)換為你相應(yīng)的效果類(lèi)。在這個(gè)方法里面,也是要調(diào)用父類(lèi)的同名方法:super.initInstance(instance);
基本上,一個(gè)工廠類(lèi)就寫(xiě)好了,但這樣只是最簡(jiǎn)單的寫(xiě)法,試想想,每個(gè)人穿衣服的Size不同,喜歡的顏色也不同,所以,是不是可以由用戶(hù)來(lái)定義他們想要的效果的顏色等屬性呢?當(dāng)然,你對(duì)衣服有什么要求,都是向工廠提出的,沒(méi)有人會(huì)對(duì)衣服說(shuō)吧?所以,這些可設(shè)置的屬性也是定義在工廠類(lèi)里面,所以下面,我們?yōu)樵撘路啥ㄖ祁伾珵槔诠S類(lèi)里面加入如下代碼:
1 private var _color:Number = 0xFF0000;
2 public function set color(value:Number):void {
3 _color = value;
4 }
你想運(yùn)行時(shí)的效果可以設(shè)置不同的顏色的話,就可以直接設(shè)置MyEffect的color屬性,之后將這個(gè)屬性傳給效果實(shí)例類(lèi):
1 override protected function initInstance(instance:EffectInstance):void {
2 super.initInstance(instance);
3 MyEffectInstance(instance).color = _color;
4 }
這些對(duì)效果實(shí)例類(lèi)的設(shè)置,都是要定在initInstance方法里了,你想對(duì)運(yùn)行時(shí)的效果設(shè)置什么屬性的話,都要先告訴工廠類(lèi),之后工廠類(lèi)在這個(gè)方法里面轉(zhuǎn)嫁給實(shí)例類(lèi),這樣,同一個(gè)效果,可以運(yùn)行不同的顏色。但前提是你后面要寫(xiě)的實(shí)例類(lèi)要有color這個(gè)屬性。
現(xiàn)在已做好了工廠類(lèi)了,下面要做效果實(shí)例類(lèi)了,先貼出完整代碼:
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 }
我們看到,每一個(gè)動(dòng)畫(huà)效果實(shí)例類(lèi),都要繼承自EffectInstance這個(gè)類(lèi),構(gòu)造函數(shù)也是需要接收一個(gè)Object,這個(gè)Object其實(shí)就是你要應(yīng)用到的組件對(duì)象,這個(gè)會(huì)是系統(tǒng)自動(dòng)傳遞的,接收了Object后還要用該Object 調(diào)用父類(lèi)的構(gòu)造函數(shù):super(newTarget);
之后還有一件必做的事,就是重寫(xiě)play()這個(gè)方法:override public function play( ):void
是不是對(duì)play()很熟悉?因?yàn)榈谝黄恼轮?,就用到這個(gè)方法來(lái)發(fā)動(dòng)效果的播放的,所以,你需要做的動(dòng)畫(huà)編程都是在這個(gè)方法里。但還是要先調(diào)用父類(lèi)的同名方法,super.play();之后的,就是你想怎么畫(huà)就怎么畫(huà)啦。我將畫(huà)一個(gè)與要應(yīng)用效果的組件一樣大小的矩型,之后該矩形會(huì)放大并透明,效果都寫(xiě)在drawShape()方法里了??吹竭@個(gè)方法里面的代碼,是不是跟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的寫(xiě)法,但是如果不用ENTER_FRAME方式制作動(dòng)畫(huà)的話,還有另外一種方法的,那就是Tween了,Tween是以“時(shí)間”為準(zhǔn),而ENTER_FRAME是以“幀”為準(zhǔn),其實(shí)到這里,一個(gè)基本的Flex自定義動(dòng)畫(huà)效果就完成了,但擴(kuò)展一下的,還可以用Tween來(lái)實(shí)現(xiàn),而且建議用Tween來(lái)寫(xiě)動(dòng)畫(huà)效果,易控制,清淅一點(diǎn)。用Tween實(shí)現(xiàn)的話,效果與寫(xiě)法都是差不多的,要用Tween就要將效果實(shí)例類(lèi)繼承自TweenEffectInstance這個(gè)類(lèi),并重寫(xiě)它的onTweenUpdate( )方法與onTweenEnd( )方法,這種Tween效果的寫(xiě)法,將會(huì)比ENTER_FRAME的寫(xiě)法方便,因?yàn)樗鶕?jù)的是時(shí)間,所以,你可以指定效果播放的時(shí)間,并且當(dāng)播放完畢會(huì)自動(dòng)調(diào)用onTweenEnd()方法,你可以在該方法里寫(xiě)一些處理操作,如釋放資源等等
由于編幅關(guān)系,就不在這里詳細(xì)介紹TweenEffectInstence了,就簡(jiǎn)單貼出該類(lèi)的寫(xiě)法與注釋吧:
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 //構(gòu)造函數(shù)
17 public function MyEffectInstance(newTarget:Object) {
18 super(newTarget);
19 }
20
21 //同樣的要重寫(xiě)play()方法與調(diào)用父類(lèi)同名方法
22 override public function play( ):void {
23 super.play();
24 drawShape(); //先創(chuàng)建一個(gè)矩形
25 /*注意:用Tween效果寫(xiě)法的話,就一定要?jiǎng)?chuàng)建一個(gè)Tween對(duì)象
26 第一個(gè)參數(shù)是偵聽(tīng)器,即偵聽(tīng)Update與End的,這兩個(gè)方法都在這個(gè)類(lèi)里,
27 所以這里就寫(xiě)this,第二和第三個(gè)參數(shù)都是一個(gè)數(shù)組
28 第二個(gè)參數(shù)是初始值數(shù)組,第三個(gè)是結(jié)果值數(shù)組,都要一一對(duì)應(yīng),第四個(gè)是變化時(shí)間
29 這里的是[1,1]分別是初始時(shí)的scale比例與alpha,[3,0]就是最終結(jié)果數(shù)值
30 系統(tǒng)會(huì)自動(dòng)在1000毫秒里平分這些值來(lái)得到漸變效果
31 并將每一次數(shù)值的改變時(shí)調(diào)用Update方法,結(jié)束后調(diào)用End方法
32 你也可以將時(shí)間的參數(shù)發(fā)布到工廠類(lèi)屬性里,可以方便設(shè)置播放時(shí)間,像Flex自帶效果一樣
33 */
34 new Tween(this,[1,1],[3,0],1000);
35 }
36
37 override public function onTweenUpdate(value:Object):void{
38 //這里將改變的數(shù)值應(yīng)用到組件對(duì)象中。注意:也要與上面的數(shù)值數(shù)組相對(duì)應(yīng)。
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 //當(dāng)播放完時(shí)會(huì)自動(dòng)調(diào)用該方法,這里就做刪除該矩形的操作吧
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 }
就寫(xiě)到這里吧,關(guān)于Tween其它的,就留作為作業(yè),讓大家思考與探索吧!之后如果有時(shí)間的話,將會(huì)寫(xiě)完下篇文章介紹Flex的“變面”動(dòng)畫(huà),即狀態(tài)變換!這里先謝謝大家支持!
posted on 2008-07-29 14:24
姜大叔 閱讀(5677)
評(píng)論(7) 編輯 收藏 所屬分類(lèi):
Flash/Flex