ParentAnimation,顾名思义,是一组Animation的父亲,是所有需要包含其它Animation的父类,我们熟悉的ParallelAnimation(并行动画)和SequenceAnimation(顺序动画)都是它的子类。从这个概念上来说,这也是个非常经典的Composit模式应用。ParentAnimation相关的UML类图如下:
构造函数:
-
ParentAnimation:比Animaion类的构造函数多一个Animation数组作为参数,作为初始化的子Animation对象。
属性:
-
animations:只读属性,Array类型。返回所有当前的子Animation。
方法:
-
add:添加一个子Animation对象。
-
clear:清除并销毁所有子Animation对象。
-
dispose:销毁当前ParentAnimation对象。
-
initialize:初始化当前ParentAnimation对象。
-
remove:删除并销毁指定的子Animation对象。
-
removeAt:删除并销毁指定下标的子Animaion对象。
ParentAnimation在Animation基础上添加了一些集合操作的方法。
在ParentAnimation的构造函数中,会得到一个数组,存放了初始情况下所有的子Animation对象,它们会被依次调用add方法添加到ParentAnimation自己维护的数组中。而在ParentAnimation的initialize方法中,会确定每个子Animation有没有被初始化,如果没有,则调用它的initialize方法。
值得注意的是,像remove,removeAt和clear这些删除子Animation的方法中(也包括dispose方法,它调用了clear方法),除了从ParentAnimation维护的数组中去除子Animation对象之外,还会将其销毁(调用其dispose方法),因此您再也无法使用这个子Animation对象了。
在ParentAnimation的add方法有个特别的地方,它是这样的实现的:
add : function(animation) { if (this._animations) { if (animation) { animation._parentAnimation = this; } Array.add(this._animations, animation); this.raisePropertyChanged('animations'); } }
可以看到,add方法在传入的animation对象中添加了一个_parentAnimation引用指向自己。那么_parentAnimation的作用是什么呢?这就要细化到我们在上一篇文章中的Animation模型了。
关键在于Animation类的target属性,这是它的实现:
get_target : function() { if (!this._target && this._parentAnimation) { return this._parentAnimation.get_target(); } return this._target; }
在target属性的getter中,如果发现当前Animation没有指定target,它则会设法通过_parentAnimation引用来寻找父Animation,并使用父Animation的target属性指定的对象。因此,我们可以仅仅在父Animation中指定target,它的所有子Animation就能统一对同一个对象进行操作了。
ParentAnimation是一种比较特别的Animation对象,因为它的作用是“组织和管理”子Animation,因此它使用的是其实是子Animation的功能,而它本身并不提供动画效果。因此它会覆盖Animation类的一些特别的方法,比如onStart、onStep和onEnd,而像SequenceAnimation甚至覆盖play,pause和stop方法。
作为示例,我们来开发一个RandomExecutionAnimation,它的作用是随机从子Animation中选择一个,并播放它的动画效果。RandomExecutionAnimation的代码如下:
Type.registerNamespace("Jeffz"); Jeffz.RandomExecutionAnimation = function(target, duration, fps, animations) { Jeffz.RandomExecutionAnimation.initializeBase(this, arguments); this._executingAnimation = null; } Jeffz.RandomExecutionAnimation.prototype = { dispose : function() { Jeffz.RandomExecutionAnimation.callBaseMethod(this, "dispose"); delete this._executingAnimation; }, onStart : function() { Jeffz.RandomExecutionAnimation.callBaseMethod(this, "onStart"); var animations = this.get_animations(); var index = Math.floor(animations.length * Math.random()); this._executingAnimation = animations[index]; this._executingAnimation.onStart(); }, onStep : function(percentage) { this._executingAnimation.onStep(percentage); }, onEnd : function(percentage) { this._executingAnimation.onEnd(); } } Jeffz.RandomExecutionAnimation.registerClass( "Jeffz.RandomExecutionAnimation", $AA.ParentAnimation);
在RandomExecutionAnimation中,我们覆盖了onStart、onStep和onEnd方法,将功能完全委托给随机选择的子Animation。因此,在子Animation中设置的duration和fps属性的效果将被忽略,它们将会完全使用RandomExecutionAnimation对象中设置的duration和fps。ParallelAnimation也使用了这种做法,因为它所有的子Animaion需要同时播放,所以ParallelAnimation就提供了一个同步调配的作用。
RandomExecutionAnimation的使用效果如下:
Fps:
在这个示例中,我在RandomExecutionAnimation中放置了3个ColorAnimation,分别用于变化元素的边框,背景和前景的颜色。大家可以多次点击Play按钮察看效果。