js_animtor

JS 属性动画 (Property Animator)

创建动画

使用 pm.createAnimator() 方法创建动画,该方法的调用形式为:

pm.createAnimator()
pm.createAnimator(duration)
pm.createAnimator(duration, interval)

参数 duration 为动画的总时长,interval 为动画的帧间隔,这两个参数也可以在动画创建之后进行修改。调用该方法将该方法返回一个新的 Animator 对象。

动画属性设置

我们可以设置一个动画对象的属性值,这些属性包括动画时长、插值器类型等各种效果,每一个属性都有专用的方法来进行设置。

Animator.duration

该方法设置动画的持续时间,参数的单位为毫秒,例如 anim.duration(1000)Animator 实例 anim 的动画时长设置为 1000ms。该属性是一个动画组的全局属性。

Animator.interval

该方法设置动画的帧间隔时间,参数的单位为毫秒,例如 anim.interval(50)Animator 实例 anim 的动画帧间隔时间设置为 50ms。该属性是一个动画组的全局属性。

Animator.interpolator

该方法设置动画的插值器。插值器的作用是决定动画的播放速度,插值器是一个定义域为 [0, 1] 的函数,且 f(0)=0, f(1)=1。

对于已经预定义的插值器,使用插值器名字即可使用,目前预定义的插值器有:

插值器名称 效果说明
linear 线性插值器,产生均匀变化的动画效果
accelerate 加速插值器,产生加速的动画效果
negexp 负指数插值器,产生减速的动画效果(动画末段急剧减速)
bounce 弹跳插值器,产生弹跳的动画效果
anticipate 开始时先向后移动一段距离,然后向前移动

例如,我们希望将动画实例设置为弹跳动画效果,可以使用 bounce 插值器:

anim.interpolator('bounce')

如果预定义的插值器不能满足需求,可以自定义插值器函数。例如使用二次函数作为插值器:

anim.interpolator(function (x) { return x * x })

Animator.timing

该方法用于设置动画的播放速度趋势(缓动效果)。该方法可以使用以下参数:

参数 缓动效果
ease-in 正常,动画速率和插值器一致
ease-out 动画速率和插值器相反(如果使用加速插值器,实际动画将会是减速效果)
ease-in-out 动画速率首先和插值器一致,然后和插值器相反

如果使用线性插值器,所有的缓动效果将变得一致。

Animator.direction

该方法设置动画方向。它可以使用以下参数:

参数 说明
normal 普通的动画模式
reverse 动画反向播放
alternate 动画在奇数次正向播放,偶数次反向播放
alternate-reverse 动画在奇数次反向播放,偶数次正向播放

Animator.repeat

该方法设置动画的重复播放次数。

Animator.finished

该方法设置动画播放完成时的回调函数。

绑定控件

为了在控件上播放动画,需要使用 Animator.bind 方法对控件进行绑定。新加入的动画将对被绑定的控件进行动画。一个 Animator 实例可以多次绑定控件。

加入动画

必须对控件进行绑定才能加入有效的动画。有一类方法可以加入新动画,这些方法的名称说明了被加入动画的属性。

Animator.width

Animator.width(tx)

对已绑定控件的宽度属性进行动画,tx 为宽度的变化量,单位为像素。

Animator.height

Animator.height(th)

对已绑定控件的高度属性进行动画,th 为高度的变化量,单位为像素。

Animator.translateX

Animator.translateX(tx)

对已绑定控件的水平位置进行动画,tx 为水平位置的变化量,单位为像素。

Animator.translateY

Animator.translateY(ty)

对已绑定控件的垂直位置进行动画,ty 为垂直位置的变化量,单位为像素。

Animator.translate

Animator.translateX(tx, ty)

对已绑定控件的位置进行动画,tx 为水平位置的变化量,ty 为垂直位置的变化量,单位为像素。

Animator.rectangle

Animator.rectangle(tx, ty, tw, th)

对已绑定控件的位置和尺寸进行动画,tx 为水平位置的变化量,ty 为垂直位置的变化量,tw 为宽度的变化量,th 为高度的变化量,单位为像素。

Animator.opacity

Animator.opacity(opacity)

对控件的不透明度进行动画,opacity 为动画结束时的不透明度,控件的不透为 0 ~ 255 之间的整数值,值越大越不透明。

Animator.background

Animator.background(color)

对控件的背景色进行动画,color 为动画结束时的背景色,颜色格式为 ARGB8888。

Animator.foreground

Animator.foreground(color)

对控件的前景色进行动画,color 为动画结束时的前景色,颜色格式为 ARGB8888。

编组动画

可以向一个 Animator 对象中加入多个动画,如果我们对这些动画进行编组,同一个编组中的动画将同时播放。多个编组之间则是是序列播放的。使用 Animator.step() 方法进行编组。

对动画进行编组之后将清空当前未编组的动画,下一次编组时将生成一个新的编组,且该编组只包含本次编组之后加入的动画。

开始、停止动画

使用 Animator.start() 方法开始动画,使用 Animator.stop() 方法结束动画。

使用 Animator.start() 方法开始一个新的动画时,会自动对未编组的动画进行编组。

不要用局部变量存储动画实例,不然可能会被 GC 掉。

使用 isPlay() 方法来获取动画的运行状态,该方法范围 true 时便是动画正在播放,否则没有播放动画。

动画的编写流程

一个简单的动画设置流程为:

  1. 创建动画
  2. 设置动画属性值
  3. 加入动画(可以加入多个动画)
  4. 开始播放动画

如果我们需要在不同动画之间使用不同的属性,使用与以下流程类似的结构:

  1. 创建动画
  2. 设置动画属性值
  3. 加入动画(可以加入多个动画)
  4. 设置新的属性值
  5. 加入动画(将具有新的属性值)
  6. 开始播放动画

我们在多次加入动画的过程(第 3、4 步)中,我们可以通过修改 Animator 的属性值(第 4 步)来更改后加入动画的属性。

我们也可以在任意位置编组动画:

var anim = pm.createAnimator()
// 使用 anim.animator 添加若干动画 ...
anim.step() // 记为“编组 1”
// 使用 anim.animator 添加若干动画 ...
anim.step() // 记为“编组 2”
// ...

调用 anim.start() 开始动画播放时,所有的编组将会顺序播放,一个编组内的动画会一起播放。上面的例子的动画流程为:

+---------+    +---------+           +---------+
| Group 1 | -> | Group 2 | -> ... -> | Group N |
+---------+    +---------+           +---------+

示例

下面的例子给出了一个页面(Page)的完整 demo:

var page = {
    onLoad: function (event) {
        // 定义弹跳插值器函数
        function bounce(x) {
            if (x < 0.292893) return 11.6569 * x * x
            if (x < 0.707107) return 0.5 + 11.6569 * (x - 0.5) * (x - 0.5)
            return 0.75 + 11.6569 * (x - 0.853553) * (x - 0.853553)
        }
        // 创建一个动画,时长为 1000ms
        var anim = pm.createAnimator(1000)
        // 设置动画初始属性,方向奇数次反转,缓动效果为 ease-in,线性插值器
        anim.direction('alternate').timing('ease-in').interpolator('linear')
        anim.bind('button1')
        anim.translateX(80) // 对button1的X轴偏移进行动画
        anim.interpolator(bounce) // 设置弹跳插值器
        anim.translateY(120) // 对button1的Y轴偏移进行动画
        this.anim = anim; // 将 anim 对象赋值到 page.anim 中以便后面使用
    },
    onButton: function(event) {
        this.anim.start() // 开始播放动画
    }
};

效果

sample

为了实现按钮被平抛后弹跳掉落的效果,我们需要控制 button1 进行两个方向的运动: * 水平方向的运动,此方向上按钮匀速运动,模拟被水平丢出的效果; * 竖直方向的运动,此方向上按钮弹跳运动,模拟掉落和反弹的效果。

首先我们使用 JavaScript 代码实现了一个 bounce 插值器函数(这个插值器已经内置,这里是为了演示使用自定义插值器的用法),插值器是一个输入值和输出值都是从 0 到 1 之间变化的函数,使用插值器可以调节动画的播放进度。在这个实例中,我们使用线性插值器来控制 button1 的水平运动,并使用弹跳插值器实现 button1 的垂直运动。

接下来我们创建了一个 1000ms 时长的动画对象并设置了一些基础属性(处于演示目的,我们在这里重复设置了一些默认属性)。接下来我们将控件 'button1' 绑定到动画对象中并对它使用沿 X 轴偏移 80px 的动画,由于前面的代码中已经使用了线性插值器,动画过程中 button1 将沿着 X 轴匀速运动。接下来要设置 button1 垂直方向的动画,首先将插值器设置为 bounce 函数并使用沿 Y 轴偏移 120px 的动画。

点击 button1 的时候会触发 onButton 回调,此时会开始播放动画。我们会发现奇数次点击时,button1 会沿右下方向“掉落”,而偶数次点击时则会沿着左上方向“倒回”,这是因为我们将动画的方向属性设置成了 alternate,这样会让动画在奇数次播放时正向播放,偶数次时反向播放。