Flex的動畫效果與變換(二)

本文出自http://www.jiangzone.com.cn/,如需轉載,請註明出處!

原文地址:http://www.jiangzone.com.cn/article.asp?id=46

在上篇文章《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 這個類,我們也不能搞特殊,我們自定義的效果也要繼承那個類,先看以下整個工廠類的代碼:

[複製到剪貼板]

CODE:

package com.jiangzone.flex.effects {

import mx.effects.Effect;

import mx.effects.EffectInstance;

public class MyEffect extends Effect {

private var _color:Number = 0xFF0000;

public function set color(value:Number):void {

_color = value;

}

public function MyEffect(newTarget:Object = null) {

super(newTarget);

instanceClass = MyEffectInstance;

}

override public function getAffectedProperties( ):Array {

return [];

}

override protected function initInstance(instance:EffectInstance):void {

super.initInstance(instance);

MyEffectInstance(instance).color = _color;

}

}

}

大家看看上面的代碼,其中先看構造函數,構造函數要接收一個默認爲空的Object對象

public function MyEffect(newTarget:Object = null)

之後在該構造函數裏面調用父類的構造函數,並且將instanceClass這個屬性設置爲你的該效果的實例類,因爲這個類是工廠類,所以要知道你這個工廠生產什麼產品,即上面說的“衣服”,所以這裏我們將其命名爲MyEffectInstance,注意:在Flex中的所有效果實例類都是在工廠類後面加Instance,也不是一定,只是規範而已。還有注意,下面一會定義的實例類的類名一定要跟這裏的一致。

大家還會看到,上面的代碼中,複寫(override)了二個方法:getAffectedProperties( )與initInstance(instance:EffectInstance)

這兩個方法都是要複寫的,先說說getAffectedProperties( )這個方法,這個方法是獲取被改變的屬性值,怎麼說呢,比如說,你做的動畫效果如果要用到組件對象的一些屬性的話,就要返回這些屬性的名字,如:你的效果是對組件做旋轉的話,則:

[複製到剪貼板]

CODE:

override public function getAffectedProperties( ):Array {

return ["rotation"];

}

反正你做的效果需要對組件修改什麼屬性的話,都在這個方法裏返回名字,修改多個屬性的話就往數組裏加就是了。

後面就是這個方法了initInstance,該方法接收一個instance:EffectInstance參數,也就是效果實例類啦,因爲每個效果實例類都要繼承EffectInstance類,所以這個方法裏的參數寫的是父類,在裏面要做其它的話,需要將 instance 轉換爲你相應的效果類。在這個方法裏面,也是要調用父類的同名方法:super.initInstance(instance);

基本上,一個工廠類就寫好了,但這樣只是最簡單的寫法,試想想,每個人穿衣服的Size不同,喜歡的顏色也不同,所以,是不是可以由用戶來定義他們想要的效果的顏色等屬性呢?當然,你對衣服有什麼要求,都是向工廠提出的,沒有人會對衣服說吧?所以,這些可設置的屬性也是定義在工廠類裏面,所以下面,我們爲該衣服可定製顏色爲例,在工廠類裏面加入如下代碼:

[複製到剪貼板]

CODE:

private var _color:Number = 0xFF0000;

public function set color(value:Number):void {

_color = value;

}

你想運行時的效果可以設置不同的顏色的話,就可以直接設置MyEffect的color屬性,之後將這個屬性傳給效果實例類:

[複製到剪貼板]

CODE:

override protected function initInstance(instance:EffectInstance):void {

super.initInstance(instance);

MyEffectInstance(instance).color = _color;

}

這些對效果實例類的設置,都是要定在initInstance方法裏了,你想對運行時的效果設置什麼屬性的話,都要先告訴工廠類,之後工廠類在這個方法裏面轉嫁給實例類,這樣,同一個效果,可以運行不同的顏色。但前提是你後面要寫的實例類要有color這個屬性。

現在已做好了工廠類了,下面要做效果實例類了,先貼出完整代碼:

[複製到剪貼板]

CODE:

package com.jiangzone.flex.effects {

import mx.effects.EffectInstance;

import flash.display.Shape;

import flash.events.Event;

public class MyEffectInstance extends EffectInstance {

private var _color:Number;

private var shape:Shape;

public function set color(value:Number):void {

_color = value;

}

public function MyEffectInstance(newTarget:Object) {

super(newTarget);

}

override public function play( ):void {

super.play( );

drawShape();

}

private function drawShape():void{

shape = new Shape();

shape.graphics.beginFill(_color);

shape.graphics.drawRect(target.width * -0.5,target.height * -0.5,target.width,target.height);

shape.graphics.endFill();

shape.x = target.x + target.width * 0.5;

shape.y = target.y + target.height * 0.5;

target.parent.rawChildren.addChild(shape);

target.addEventListener(Event.ENTER_FRAME,onEnterFrame);

}

private function onEnterFrame(e:Event):void{

shape.scaleX += 0.1;

shape.scaleY += 0.1;

shape.alpha -= 0.05;

if(shape.alpha <= 0){

target.parent.rawChildren.removeChild(shape);

target.removeEventListener(Event.ENTER_FRAME,onEnterFrame);

}

}

}

}

我們看到,每一個動畫效果實例類,都要繼承自EffectInstance這個類,構造函數也是需要接收一個Object,這個Object其實就是你要應用到的組件對象,這個會是系統自動傳遞的,接收了Object後還要用該Object 調用父類的構造函數:super(newTarget);

之後還有一件必做的事,就是重寫play()這個方法:override public function play( ):void

是不是對play()很熟悉?因爲第一篇文章中,就用到這個方法來發動效果的播放的,所以,你需要做的動畫編程都是在這個方法裏。但還是要先調用父類的同名方法,super.play();之後的,就是你想怎麼畫就怎麼畫啦。我將畫一個與要應用效果的組件一樣大小的矩型,之後該矩形會放大並透明,效果都寫在drawShape()方法裏了。看到這個方法裏面的代碼,是不是跟Flash裏的一樣了?

這裏先看看最終效果:

在這裏,我用了ENTER_FRAME的寫法,但是如果不用ENTER_FRAME方式製作動畫的話,還有另外一種方法的,那就是Tween了,Tween是以“時間”爲準,而ENTER_FRAME是以“幀”爲準,其實到這裏,一個基本的Flex自定義動畫效果就完成了,但擴展一下的,還可以用Tween來實現,而且建議用Tween來寫動畫效果,易控制,清淅一點。用Tween實現的話,效果與寫法都是差不多的,要用Tween就要將效果實例類繼承自TweenEffectInstance這個類,並重寫它的onTweenUpdate( )方法與onTweenEnd( )方法,這種Tween效果的寫法,將會比ENTER_FRAME的寫法方便,因爲它根據的是時間,所以,你可以指定效果播放的時間,並且當播放完畢會自動調用onTweenEnd()方法,你可以在該方法裏寫一些處理操作,如釋放資源等等

由於編幅關係,就不在這裏詳細介紹TweenEffectInstence了,就簡單貼出該類的寫法與註釋吧:

[複製到剪貼板]

CODE:

package com.jiangzone.flex.effects {

import mx.effects.effectClasses.TweenEffectInstance;

import flash.display.Shape;

import flash.events.Event;

import mx.effects.Tween;

public class MyEffectInstance extends TweenEffectInstance {

private var _color:Number;

private var shape:Shape;

public function set color(value:Number):void {

_color = value;

}

//構造函數

public function MyEffectInstance(newTarget:Object) {

super(newTarget);

}

//同樣的要重寫play()方法與調用父類同名方法

override public function play( ):void {

super.play();

drawShape(); //先創建一個矩形

/*注意:用Tween效果寫法的話,就一定要創建一個Tween對象

第一個參數是偵聽器,即偵聽Update與End的,這兩個方法都在這個類裏,

所以這裏就寫this,第二和第三個參數都是一個數組

第二個參數是初始值數組,第三個是結果值數組,都要一一對應,第四個是變化時間

這裏的是[1,1]分別是初始時的scale比例與alpha,[3,0]就是最終結果數值

系統會自動在1000毫秒裏平分這些值來得到漸變效果

並將每一次數值的改變時調用Update方法,結束後調用End方法

你也可以將時間的參數發佈到工廠類屬性裏,可以方便設置播放時間,像Flex自帶效果一樣

*/

new Tween(this,[1,1],[3,0],1000);

}

override public function onTweenUpdate(value:Object):void{

//這裏將改變的數值應用到組件對象中。注意:也要與上面的數值數組相對應。

shape.scaleX = Number(value[0]);

shape.scaleY = Number(value[0]);

shape.alpha = Number(value[1]);

}

override public function onTweenEnd(value:Object):void {

//當播放完時會自動調用該方法,這裏就做刪除該矩形的操作吧

target.parent.rawChildren.removeChild(shape);

}

private function drawShape():void{

shape = new Shape();

shape.graphics.beginFill(_color);

shape.graphics.drawRect(target.width * -0.5,target.height * -0.5,target.width,target.height);

shape.graphics.endFill();

shape.x = target.x + target.width * 0.5;

shape.y = target.y + target.height * 0.5;

target.parent.rawChildren.addChild(shape);

}

}

}

就寫到這裏吧,關於Tween其它的,就留作爲作業,讓大家思考與探索吧!之後如果有時間的話,將會寫完下篇文章介紹Flex的“變面”動畫,即狀態變換!這裏先謝謝大家支持!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章