代码改变世界

Animation全接触(2):ParentAnimation模型

2007-03-16 15:16 Jeffrey Zhao 阅读(...) 评论(...) 编辑 收藏

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的使用效果如下:

Hello World
Duration:
Fps:

 

在这个示例中,我在RandomExecutionAnimation中放置了3个ColorAnimation,分别用于变化元素的边框,背景和前景的颜色。大家可以多次点击Play按钮察看效果。