整理转载自:http://www.blogjava.net/cph8066/archive/2008/07/29/218405.html
在Flex里面不像在Flash里面随意制作动画了,Flex更趋向于应用程序,而不是动画制作了,所以没有了时间轴的概念。在Flex中使用动画效果, 可以用Flex自带的Effect,或者自已定制Effect,因为很多人都想借Flash里面的一样操作Flex,比如在Flash里面做一个动态按钮 很容易,当鼠标移动到上面时,会有很多发光的点跑出来(荧火虫效果),这种效果在Flash十分容易实现,但在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()方法:
先看效果:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”>
<mx:Script>
<![CDATA[
private function onClick(event:Event):void
{
be.target = event.currentTarget;
be.play( );
}
]]>
</mx:Script>
<mx:Blur id=”be” blurXTo=”50″ blurYTo=”50″ duration=”1000″ />
<mx:Panel id=”p” width=”200″ height=”180″ click=”onClick(event)” />
</mx:Application>
在代码中看到,要使用效果,先定好一个效果,在Panel的点击事件里再对该效果进行一些设置,如be.target = event.currentTarget 设置该效果将要应用到的目标组件(Component),之后再调用play()方法后,该效果就会应用在Panel上面播放!
(2)使用触发器播放效果:
使用触发器播放效果的话,可以不用写ActionScript代码,直接在组件的效果触发器上指明使用哪个效果就可以了,比较简单明了,但就不能进行更多的属性定制,先看看触发器播放的代码:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”>
<mx:Blur id=”be” blurXTo=”50″ blurYTo=”50″ duration=”2000″ />
<mx:Panel id=”p” width=”200″ height=”180″ creationCompleteEffect=”{be}” />
</mx:Application>
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
你可以在该效果事件的处理函数里面对效果作相应的操作,如:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”>
<mx:Script>
<![CDATA[
import mx.events.EffectEvent;
public function onEffEnd(e:EffectEvent):void
{
e.effectInstance.reverse();
e.effectInstance.play();
}
]]>
</mx:Script>
<mx:Blur id=”be” blurXTo=”50″ blurYTo=”50″ duration=”2000″ />
<mx:Panel id=”p” width=”200″ height=”180″ creationCompleteEffect=”{be}” effectEnd=”onEffEnd(event)” />
</mx:Application>
当效果播放完时,系统将会自动触发effectEnd事件,在处理函数里面,将该效果Instance即现时播放的效果实例进行倒转并播放,当播放完,又会触发effectEnd事伯,这样一直循环!
效果的组合:
通常如果你觉得只应用一个效果很单调的话,可以进行效果组合应用,即多个效果同时播放或者顺序播放,
如, 当加载页面时,你想Panel先模糊到一定程度,再将Panel移动到某个位置,再把Panel还原成原来的清淅度。一共用了三个效果,一,先应用Blur效果,当Blur完成时,再应用Move效果,当Move完成时,再应用另外一个Blur(由模至清)效果。 这样三个效果组合就是按顺序组合,先后运行。
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”>
<mx:Sequence id=”sequenceEffect”>
<mx:Blur id=”beOut” blurXTo=”50″ blurYTo=”50″ duration=”500″ />
<mx:Move id=”mv” xTo=”200″ yTo=”150″ duration=”500″ />
<mx:Blur id=”beIn” blurXFrom=”50″ blurYFrom=”50″ blurXTo=”0″ blurYTo=”0″ duration=”500″ />
</mx:Sequence>
<mx:Panel id=”p” width=”200″ height=”180″ mouseDownEffect=”sequenceEffect” />
</mx:Application>
看以上代码,<mx:Sequence id=”sequenceEffect”>标签就是顺序组合效果标签,当应用sequenceEffect效果的时候,它会按顺序播放该标签里面的三个子效果。
另外的就是同时播放了,
<mx:Parallel id=”parallelEffect”>
<mx:Blur id=”beOut” blurXTo=”50″ blurYTo=”50″ duration=”500″ />
<mx:Move id=”mv” xTo=”200″ yTo=”150″ duration=”500″ />
</mx:Parallel>
<mx:Parallel>标签就是同时播放的效果标签,放在它里面的子效果都会同时播放,即一边模糊一边移动。这个都可以自由组合,<mx:Parallel>与 <mx:Sequence>标签都可以自由组合。这里就不多说了。
很多开发者都并不满足Flex里提供的简单的渐变大小,透明,移动,遮罩等的效果。在Flash,多数人都是随意的制作一些动画效果,而且形态多变。在Flex里也可以自定义动画效果,只不过就是没有Flash里面那么简单随意了。不过熟悉了之后,也会觉得在 Flex里制作动画也不是什么难事。
在这里我先介绍一下Flex里面的动画效果机制,在Flex里面要使用动画效果的话,先要创建一个效果标签,之后在组件里(如TextInput)写上效果触发器。
但可能会有人问,如果程序里我就只定义一个移动效果< mx:Move>,之后我程序里面有5个组件,每个组件的动画效果都指向这个Move效果,那么它是不是组件一运行了效果后,组件二再触发效果?
其实它不是,虽然我们只定义了一个Move,但我们定义的只是Move效果的工厂,这里就用到了设计模式中的 “工厂方法”模式,其实5个组件都可以同时运行效果,而5个效果都是不同的一个实例,彼此独立。
效果运行的时候,其实运行的不是Move这个对象,而是MoveInstance这个对象,Move只是工厂。
我们就先建造一个工厂吧!
在Flex里面所有的效果的工厂都是继承自 mx.effects.Effect 这个类,先看以下整个工厂类的代码:
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 MyEffect(newTarget:Object = null) // 构造函数
{
super(newTarget); // 调用父类的构造函数
// 这个MyEffect 类是工厂类。在Flex中的所有效果实例类都是在工厂类后面加 Instance,也不是一定,只是规范而已
instanceClass = MyEffectInstance;
}
public function set color(value:Number):void
{
_color = value;
}
// 重写了父类的getAffectedProperties方法
override public function getAffectedProperties( ):Array // 这个方法是获取被改变的属性值
{
return [];
}
// 重写了父类的initInstance方法
override protected function initInstance(instance:EffectInstance):void // 重写了父类的方法
{
super.initInstance(instance);
MyEffectInstance(instance).color = _color;
}
}
}
重写(override)了二个方法,这两个方法都是要复写的,getAffectedProperties( )这个方法是获取被改变的属性值,比如说,你做的动画效果如果要用到组件对象的一些属性的话,就要返回这些属性的名字,如:你的效果是对组件做旋转的话,则:
override public function getAffectedProperties( ):Array
{
return ["rotation"];
}
你做的效果需要对组件修改什么属性的话,都在这个方法里返回名字,修改多个属性的话就往数组里加就是了。
initInstance(instance:EffectInstance)方法,该方法接收一个instance:EffectInstance参数,也就是效果实例,每个效果实例类都要继承EffectInstance类,在里面要做其它处理的话,也可以将 instance 转换为相应的效果类。
在这个方法里面,也是要调用父类的同名方法:super.initInstance(instance);
下面以衣服可定制颜色为例,工厂类里面如下代码:
private var _color:Number = 0xFF0000;
public function set color(value:Number):void
{
_color = value;
}
如果想运行时设置不同的颜色的话,可以直接设置MyEffect的color属性,之后将这个属性传给效果实例类:
override protected function initInstance(instance:EffectInstance):void
{
super.initInstance(instance);
MyEffectInstance(instance).color = _color;
}
你想对运行时的效果设置什么属性的话,都要先告诉工厂类,之后工厂类在这个方法里面生成实例类,这样,同一个效果,可以运行不同的颜色。但前提是你后面要写的实例类要有color这个属性。
现在已做好了工厂类了,下面写效果实例类代码:
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 MyEffectInstance(newTarget:Object) // 构造方法
{
super(newTarget);
}
public function set color(value:Number):void // 设置颜色
{
_color = value;
}
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);
}
}
}
}
我将画一个与要应用效果的组件一样大小的矩型,之后该矩形会放大并透明,效果都写在drawShape()方法里了。看到这个方法里面的代码,是不是跟Flash里的一样了?
这里再贴上MXML代码:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application layout=”absolute” xmlns:mx=”http://www.adobe.com/2006/mxml”
xmlns:pf=”com.jiangzone.flex.effects.*”>
<pf:MyEffect id=”myEffect” color=”0xFFFFFF” />
<mx:VBox x=”100″ y=”43″>
<mx:TextInput focusInEffect=”{myEffect}” />
<mx:TextInput focusInEffect=”{myEffect}” />
<mx:TextInput focusInEffect=”{myEffect}” />
<mx:TextInput focusInEffect=”{myEffect}” />
</mx:VBox>
</mx:Application>
在这里,我用了ENTER_FRAME的写法,但是如果不用ENTER_FRAME方式制作动画的话,还有另外一种方法的,那就是Tween了,Tween 是以“时间”为准,而ENTER_FRAME是以“帧”为准,其实到这里,一个基本的Flex自定义动画效果就完成了,但扩展一下的,还可以用Tween 来实现,而且建议用Tween来写动画效果,易控制,清淅一点。
用Tween实现的话,效果与写法都是差不多的,要用Tween就要将效果实例类继承TweenEffectInstance类,并重写它的onTweenUpdate( )方法与onTweenEnd( )方法,这种Tween效果的写法,将会比ENTER_FRAME的写法方便,因为它根据的是时间,所以,你可以指定效果播放的时间,并且当播放完毕会自动调用onTweenEnd()方法,你可以在该方法里写一些处理操作,如释放资源等等;由于编幅关系,就不在这里详细介绍TweenEffectInstence了,就简单贴出该类的写法:
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 MyEffectInstance(newTarget:Object) //构造函数
{
super(newTarget);
}
public function set color(value:Number):void
{
_color = value;
}
override public function play( ):void //重写play()方法
{
super.play();
drawShape(); //先创建一个矩形
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);
}
}
}
下面讲Flex中的“变面”技术,即是Transitions!
如果看过Flex SDK里面的自带的例子程序,有一个叫“Flex Store”的应用,在里面的手机列表中看某一个手机的详细时,就是这种效果。
这种的变换不难实现,看看代码再解析:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” width=”695″ height=”555″>
<mx:states>
<mx:State name=”A”>
<mx:SetProperty target=”{windowA}” name=”width” value=”500″/>
<mx:SetProperty target=”{windowA}” name=”height” value=”300″/>
<mx:SetProperty target=”{windowC}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowC}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowC}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowD}” name=”x” value=”373″/>
<mx:SetProperty target=”{windowD}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowD}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowD}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowB}” name=”x” value=”23″/>
<mx:SetProperty target=”{windowB}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowB}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowB}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowC}” name=”x” value=”200″/>
</mx:State>
<mx:State name=”B”>
<mx:SetProperty target=”{windowD}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowD}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowC}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowC}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowA}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowA}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowB}” name=”width” value=”500″/>
<mx:SetProperty target=”{windowB}” name=”height” value=”300″/>
<mx:SetProperty target=”{windowA}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowC}” name=”x” value=”200″/>
<mx:SetProperty target=”{windowC}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowB}” name=”x” value=”23″/>
<mx:SetProperty target=”{windowD}” name=”x” value=”373″/>
<mx:SetProperty target=”{windowD}” name=”y” value=”333″/>
</mx:State>
<mx:State name=”C”>
<mx:SetProperty target=”{windowD}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowD}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowB}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowB}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowA}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowA}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowC}” name=”width” value=”500″/>
<mx:SetProperty target=”{windowC}” name=”height” value=”300″/>
<mx:SetProperty target=”{windowA}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowB}” name=”x” value=”200″/>
<mx:SetProperty target=”{windowB}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowC}” name=”x” value=”23″/>
<mx:SetProperty target=”{windowC}” name=”y” value=”19″/>
<mx:SetProperty target=”{windowD}” name=”x” value=”373″/>
<mx:SetProperty target=”{windowD}” name=”y” value=”333″/>
</mx:State>
<mx:State name=”D”>
<mx:SetProperty target=”{windowC}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowC}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowB}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowB}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowA}” name=”width” value=”150″/>
<mx:SetProperty target=”{windowA}” name=”height” value=”150″/>
<mx:SetProperty target=”{windowD}” name=”width” value=”500″/>
<mx:SetProperty target=”{windowD}” name=”height” value=”300″/>
<mx:SetProperty target=”{windowA}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowB}” name=”x” value=”200″/>
<mx:SetProperty target=”{windowB}” name=”y” value=”333″/>
<mx:SetProperty target=”{windowD}” name=”x” value=”23″/>
<mx:SetProperty target=”{windowD}” name=”y” value=”19″/>
<mx:SetProperty target=”{windowC}” name=”x” value=”373″/>
<mx:SetProperty target=”{windowC}” name=”y” value=”333″/>
</mx:State>
</mx:states>
<mx:transitions>
<mx:Transition fromState=”*” toState=”*”>
<mx:Parallel targets=”{[windowA, windowB, windowC, windowD]}”>
<mx:Move />
<mx:Resize />
</mx:Parallel>
</mx:Transition>
</mx:transitions>
<mx:TitleWindow id=”windowA” x=”23″ y=”19″ width=”250″ height=”200″ layout=”absolute” title=”A” click=”currentState=’A'” />
<mx:TitleWindow id=”windowB” x=”309″ y=”19″ width=”250″ height=”200″ layout=”absolute” title=”B” click=”currentState=’B'” />
<mx:TitleWindow id=”windowC” x=”23″ y=”260″ width=”250″ height=”200″ layout=”absolute” title=”C” click=”currentState=’C'” />
<mx:TitleWindow id=”windowD” x=”309″ y=”260″ width=”250″ height=”200″ layout=”absolute” title=”D” click=”currentState=’D'” />
</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>,我们来看看变换标签的代码:
<mx:Transition fromState=”*” toState=”*”>
<mx:Parallel targets=”{[windowA, windowB, windowC, windowD]}”>
<mx:Move />
<mx:Resize />
</mx:Parallel>
</mx:Transition>
formState 与toState属性设置该状态变换是怎样触发的,里面要填上状态的名字,如果你formState=”A”,toState=”C”的话,只有从A状态 切换到C状态时,才会产生以上的变换动画效果,如果不附合该规则如A切换到B状态的话,则只会按状态的属性设置值来直接生成视图,而没有动画渐变效果了。 如果填上“*”的话,就是无论是哪个状态切换到哪个,都会运行动画效果,至于变换期间用到哪种动画效果来进行渐变,就在它的下级标签里定义了,这里它用到 了<mx:Parallel>并列播放移动与重整大小的动画效果。
基本上,一个变换就做好了,但我们还需要触发它,也就是去改变程序当前的显示状态:click =”currentState=’A'” 在每个组件的click事件里,改变程序的currentState值,就是改变程序的当前显示状态!之后动画效果就会触发了!