rh 发现很久没有写BLOG了,罪过罪过,先忙着找工作,工作搞定了,又忙着毕业论文,现在终于有时间来做做Flex了,手生了些,没有项目,完全自娱自乐型。
TweenEffect,补间效果~是一种渐变的类型,像Glow,Move等都是TweenEffect的子类,自已做一个TweenEffect,应该在很多场合用得到。
首先选取一个TweenEffect来研究一下,就Glow吧,找到它的原代码,如下(去掉了注释,加上自己的注释 ):
package mx.effects { import mx.effects.effectClasses.GlowInstance; import mx.styles.StyleManager; public class Glow extends TweenEffect { include "../core/Version.as"; public function Glow(target:Object = null) { super(target); instanceClass = GlowInstance; } /*添加一些效果参数,用Inspectable标签声明,这样可以在MXML上设置这些属性*/ [Inspectable(category="General", defaultValue="NaN")] public var alphaFrom:Number; [Inspectable(category="General", defaultValue="NaN")] public var alphaTo:Number; [Inspectable(category="General", defaultValue="NaN")] public var blurXFrom:Number; [Inspectable(category="General", defaultValue="NaN")] public var blurXTo:Number; [Inspectable(category="General", defaultValue="NaN")] public var blurYFrom:Number; [Inspectable(category="General", defaultValue="NaN")] public var blurYTo:Number; [Inspectable(category="General", format="Color", defaultValue="0xFFFFFFFF")] public var color:uint = StyleManager.NOT_A_COLOR; [Inspectable(category="General", defaultValue="false")] public var inner:Boolean; [Inspectable(defaultValue="false")] public var knockout:Boolean; [Inspectable(category="General", defaultValue="2")] public var strength:Number; override public function getAffectedProperties():Array /* of String */ { return AFFECTED_PROPERTIES; } override protected function initInstance(instance:IEffectInstance):void { super.initInstance(instance); //创建效果实例 var glowInstance:GlowInstance = GlowInstance(instance); //将参数传递给实例 glowInstance.alphaFrom = alphaFrom; glowInstance.alphaTo = alphaTo; glowInstance.blurXFrom = blurXFrom; glowInstance.blurXTo = blurXTo; glowInstance.blurYFrom = blurYFrom; glowInstance.blurYTo = blurYTo; glowInstance.color = color; glowInstance.inner = inner; glowInstance.knockout = knockout; glowInstance.strength = strength; } } }
真的是so easy,Glow ms就是用来创建实例,外加传递参数的。在设计模式中叫工厂,看来关键还是有GlowInstance类里面,再找到GlowInstance类的代码。
package mx.effects.effectClasses { import flash.events.Event; import flash.filters.GlowFilter; import mx.core.Application; import mx.core.mx_internal; import mx.styles.StyleManager; public class GlowInstance extends TweenEffectInstance { include "../../core/Version.as"; public function GlowInstance(target:Object) { super(target); } public var alphaFrom:Number; public var alphaTo:Number; public var blurXFrom:Number; public var blurXTo:Number; public var blurYFrom:Number; public var blurYTo:Number; public var color:uint = StyleManager.NOT_A_COLOR; public var inner:Boolean; public var knockout:Boolean; public var strength:Number; override public function initEffect(event:Event):void { super.initEffect(event); } override public function play():void { super.play(); if (isNaN(alphaFrom)) alphaFrom = 1.0; if (isNaN(alphaTo)) alphaTo = 0; if (isNaN(blurXFrom)) blurXFrom = 5; if (isNaN(blurXTo)) blurXTo = 0; if (isNaN(blurYFrom)) blurYFrom = 5; if (isNaN(blurYTo)) blurYTo = 0; if (color == StyleManager.NOT_A_COLOR) color = Application.application.getStyle("themeColor"); if (isNaN(strength)) strength = 2; tween = createTween( this, [ color, alphaFrom, blurXFrom, blurYFrom ], [ color, alphaTo, blurXTo, blurYTo ], duration); } override public function onTweenUpdate(value:Object):void { setGlowFilter(value[0], value[1], value[2], value[3]); } override public function onTweenEnd(value:Object):void { setGlowFilter(value[0], value[1], value[2], value[3]); super.onTweenEnd(value); } private function setGlowFilter (color:uint, alpha:Number, blurX:Number, blurY:Number):void { var filters:Array = target.filters; var n:int = filters.length; for (var i:int = 0; i < n; i++) { if (filters[i] is GlowFilter) filters.splice(i, 1); } if (blurX || blurY || alpha) filters.push(new GlowFilter(color, alpha, blurX, blurY, strength, 1, inner, knockout)); target.filters = filters; } } }
稍微有点复杂了,仔细看看,也还好,开始定义一些参数,就里面参数与Glow中定义是一致的,然后重写了一些关键函数。看看这些函数都干嘛的。
play():动画开始播放,首先检查参数,如果没有值,就加上默认值。最后一句是关键,
tween = createTween( this, [ color, alphaFrom, blurXFrom, blurYFrom ], [ color, alphaTo, blurXTo, blurYTo ], duration);
它创建了一个Tween,参数中两个数组很有意思,是一一对应的,一个是From,另一个就是To,这个Tween动画就是这样产生的,数组中的参数,从From淅变到To,中间会停地派发TweenUpdate事件,在类中对这一事件进行处理,实现淅变的效果。
TweenUpdate事件便是在onTweenUpdate()函数中得到处理,参数value是From与To之间的中间值,我们根据这个值来做动画,Glow调用的是setGlowFilter()函数来实现。
在Tween结束时,即达到To了,就会派发TweenEnd事件,所以也要重写onTweenEnd()函数。
好了,都研究完了,ms可以动手写个自己的TweenEffect了,写了个,先看效果,
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="300" height="300" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"> <param name="src" value="http://www.mjbox.com/r/io/ioryioryzhan/TestRound.swf"> <embed type="application/x-shockwave-flash" width="300" height="300" src="http://www.mjbox.com/r/io/ioryioryzhan/TestRound.swf"></embed></object>
javaeye变垃圾了吗,连个flash贴进去总是出问题,(http://www.mjbox.com/r/io/ioryioryzhan/TestRound.swf ) 这个是链接
点start按扭,可以看到,一个框框围着控件,一个球球在沿着框框移动,好像不怎么美观,将就一点。它是完成依照Glow编写的,叫Round,Round代码如下:
package effects { import mx.effects.IEffectInstance; import mx.effects.TweenEffect; public class Round extends TweenEffect { [Inspectable(category="General", defaultValue="NaN")] public var lineColor:uint; [Inspectable(category="General", defaultValue="NaN")] public var lineWeight:Number; [Inspectable(category="General", defaultValue="NaN")] public var circleColor:uint; [Inspectable(category="General", defaultValue="NaN")] public var circleRadio:Number; [Inspectable(category="General", defaultValue="NaN")] public var distance:Number; public function Round(target:Object=null) { super(target); this.instanceClass = RoundInstance; } override protected function initInstance(instance:IEffectInstance):void{ super.initInstance(instance); var roundInstance:RoundInstance = RoundInstance(instance); roundInstance.lineColor = lineColor; roundInstance.lineWeight = lineWeight; roundInstance.circleColor = circleColor; roundInstance.circleRadio = circleRadio; roundInstance.distance = distance; } } }
不同点在于instanceClass不同了,还有就是参数不同。
没有注释,稍微讲讲这些参数,主要设置线的宽度,颜色,小圆圈的半径,颜色,还有框框与控件的距离。
下面是RoundInstance的代码:
package effects { import flash.events.Event; import mx.core.UIComponent; import mx.core.UIComponentGlobals; import mx.effects.effectClasses.TweenEffectInstance; import mx.core.mx_internal; use namespace mx_internal; public class RoundInstance extends TweenEffectInstance { public var lineColor:uint; public var lineWeight:Number; public var circleColor:uint; public var circleRadio:Number; public var distance:Number; public function RoundInstance(target:Object) { super(target); } override public function initEffect(event:Event):void{ super.initEffect(event); } override public function play():void{ if (isNaN(lineColor)) lineColor = 0xff0000; if (isNaN(circleColor)) circleColor = 0xff0000; if (isNaN(distance)) distance = 3; if (isNaN(lineWeight)) lineWeight = 1; if (isNaN(circleRadio)) circleRadio = 3; //保证参数合理性 if(distance<=0){ distance = 3; } if(lineWeight > 2 * distance){ lineWeight = 2 * distance; } if(circleRadio > distance){ circleRadio = distance; } var targetUI:UIComponent = target as UIComponent; var w:Number = targetUI.width; var h:Number = targetUI.height; //创建Tween tween = createTween(this,[0],[2*(w+2*distance)+2*(h+2*distance)],duration); } override public function onTweenUpdate(value:Object):void{ draw(value[0]); } override public function onTweenEnd(value:Object):void{ var targetUI:UIComponent = target as UIComponent; targetUI.graphics.clear(); super.onTweenEnd(value); } private function draw(d:Number):void{ var targetUI:UIComponent = target as UIComponent; targetUI.graphics.clear(); targetUI.graphics.lineStyle(lineWeight,lineColor); targetUI.graphics.moveTo(-distance,-distance); targetUI.graphics.lineTo(-distance,targetUI.height+distance); targetUI.graphics.lineTo(targetUI.width + distance,targetUI.height+distance); targetUI.graphics.lineTo(targetUI.width + distance,-distance); var x:Number; var y:Number; var h:Number = targetUI.height + 2*distance; var w:Number = targetUI.width + 2*distance; if(d<h){ x = -distance; y = d; }else if(d>=h&&d<(w+h)){ x = d - h; y = h - distance; }else if(d>=(w+h)&&d<(w+2*h)){ x = w - distance; y = w + 2* h - d; }else{ x = 2*w + 2* h - d; y = - distance; } targetUI.graphics.beginFill(circleColor); targetUI.graphics.drawCircle(x,y,circleRadio); targetUI.graphics.endFill(); } } }
看看Tween的创建
tween = createTween(this,[0],[2*(w+2*distance)+2*(h+2*distance)],duration);
从0开始,一直到2*(w+2*distance)+2*(h+2*distance),进行淅变,这个长表达式就是框框的周长,
draw函数,便是以中间值,计算当前球球的位置,进行绘制。
主程序,很简单,三个按扭,
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()" backgroundColor="0xffffff" xmlns:myeffect="effects.*" width="300" height="300"> <mx:Script> <![CDATA[ import mx.effects.Effect; import mx.events.EffectEvent; import mx.effects.Glow; import effects.Round; internal function init():void{ } internal function onClickBtn2(e:MouseEvent):void{ round1.play(); } internal function onClickBtn3(e:MouseEvent):void{ round1.end(); } ]]> </mx:Script> <myeffect:Round id="round1" target="{btn}" lineColor="0xff0000" lineWeight="1" circleColor="0x0000ff" circleRadio="3" distance="10" duration="2000"/> <mx:Button x="50" y="50" width="90" height="50" id="btn" label="Button"/> <mx:Button x="50" y="200" width="90" height="50" id="btn2" label="start"click="onClickBtn2(event)"/> <mx:Button x="150" y="200" width="90" height="50" id="btn3" label="end" click="onClickBtn3(event)"/> </mx:Application>
点击调试,ft,出问题了,框框也有,球也有,也转的挺好,就是转完后不消失,我记得在onTweenEnd()中已经将画布clear()了,看来是super.onTweenEnd();有问题,点进去看看,果然是它,
/*in Class TweenEffectInstance*/ public function onTweenEnd(value:Object):void { onTweenUpdate(value); tween = null; if (mx_internal::needToLayout) UIComponentGlobals.layoutManager.validateNow(); finishRepeat(); }
它在里面最后还是调用了一次onTweenUpdate(),所以又将框框球球画了上去,会消失才怪,只好,将下面四行代码移到RoundInstance类的onTweenUpdate()里去,修改代码:
/*in Class RoundInstance*/ override public function onTweenEnd(value:Object):void{ var targetUI:UIComponent = target as UIComponent; targetUI.graphics.clear(); //下面四行代码,是从父类中移过来的 tween = null; if (mx_internal::needToLayout) UIComponentGlobals.layoutManager.validateNow(); finishRepeat(); }
现在开以了,点击运行,就是上面flash所展示的程序了。
欢迎批评指教~~
另外求教:
RepeatCount是如何发挥作用的,相关代码在哪 ?