这篇文章我将向你展示,如何定制属于你自己的动画插值器。就像前面文章所讲的,动画系统已经提供了一系列的插值器供你选择。但是有时候你会有不一样的需求,并且你希望你的插值器有些微的不同。你可以改变已有的插值器甚至创建你自己的插值器。在文章末尾,我将创建一个新的 HesitateInterpolator 插值器作为示范。这个插值器使得动画全速启动,然后减速到一半,再加速直到动画结束。但是在此之前,我先讲讲插值器的理论知识,并向你展示如何定制已有的系统插值器。
一点理论知识
想要知道如何实现一个插值器之前,我们必须理解一个插值器到底做了什么。动画在开始时间和结束时间之间执行,每一帧都在这期间的一个特定时间显示。这个特定时间就是一个时间指数,0.0 到 1.0 闭区间中的一个 float 类型的数字。0.0 表示动画开始,1.0 表示动画结束。最简单的场景是,这个值直接被用于计算动画执行对象的变化。这种情况下,0.0 对应着动画的起始位置,1.0 对应着结束位置,0.5 表示一半,即起始位置和中间位置的正中间。这就是 LinearInterpolator(线性插值器)所做的事情。时间变化 30%,View 对应移动 30% 的距离。
一般来说,这个时间指数并不是直接用来计算动画的变化值。我们可以改变时间指数的值,使其以其他值的方式也能从 0.0 走到 1.0,而不是按照固定不变的方式运行。这就是插值器所做的事情。
一个时间插值器基本上也是一个数学公式,从 0.0 到 1.0 之间取一个值,然后变化为另一个值。下图向我们展示了加速度插值器的变化规律。View 以零速度启动,然后朝着结束位置加速变化。
默认情况下,加速度插值器的数学公式使用的是:
这里的 y 值表示插值器的输出值,t 值表示时间指数。加速度插值器可以通过一个参数实现定制化。通常,加速度插值器使用的这个公式这样表示:
f 作为一个因子,用于强调加速度的的变化。f 值越大,意味着 View 启动越慢,然后以更快的速度结束。另一方面,f 值为 1 时展示出的效果与线性插值器(Linear Interpolator)一致。
定制化插值器
大部分系统插值器都可以使用 XML 资源文件或者动态编程的方式实现定制化。通过 XML 资源定制化插值器的话,你必须在 res/anim 目录下创建一个新的 XML 文件。比如,我们想修改加速度插值器,设置 f 因子的值为 2,创建一个新文件:
res/anim/my_accelerate_interpolator.xml
<?xml version="1.0" encoding="utf-8"?>
<accelerateInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="2" />
注意:指定插值器的标签使用的是对应插值器的类名,但是第一个字母改为小写字母。然后你就可以像平时那样,在动画资源文件中简单地通过引用方式使用这个自定义的插值器:
@anim/my_accelerate_interpolator
举个例子,在 Scale 动画中使用:
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/my_accelerate_interpolator"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:duration="300" />
插值器一览
Linear Interpolator(线性插值器)
类名:
LinearInterpolator
资源 id:
@android:anim/linear_interpolator
标签名:
linearInterpolator
数学公式:
y = t
类构造函数:
public LinearInterpolator()
属性:
无
Accelerate Interpolator(加速度插值器)
类名:
AccelerateInterpolator
资源 id:
@android:anim/accelerate_interpolator
标签名:
accelerateInterpolator
数学公式:
y = t
类构造函数:
public AccelerateInterpolator(float factor)
参数:
名称:f
属性:android:factor
描述:加速度的变化速率
值越大,动画初始移动速度越慢,然后以更快的速度运动至结束。
Decelerate Interpolator(减速度插值器)
类名:
DecelerateInterpolator
资源 id:
@android:anim/decelerate_interpolator
标签名:
decelerateInterpolator
数学公式:
y = 1 - (1 - t)
类构造函数:
public DecelerateInterpolator(float factor)
参数:
名称:f
属性:android:factor
描述:减速度的变化速率。
值越大,动画初始移动速度越快,然后以更慢的速度运动至结束。
Accelerate Decelerate Interpolator(先加速后减速插值器)
类名:
AccelerateDecelerateInterpolator
资源 id:
@android:anim/accelerate_decelerate_interpolator
标签名:
accelerateDecelerateInterpolator
数学公式:
y = cos((t + 1)π)/2 + 0.5
类构造函数:
public AccelerateDecelerateInterpolator()
参数:
无
Anticipate Interpolator(张力加速器)
类名:
AnticipateInterpolator
资源 id:
@android:anim/anticipate_interpolator
标签名:
anticipateInterpolator
数学公式:
y = (T + 1) × t – T × t
类构造函数:
public AnticipateInterpolator(float tension)
参数:
名称:T
属性:android:tension
描述:反向张力值,默认值为 2。
值越大,初始化反向张力越大,运动也越快
Overshoot Interpolator(越界加速器)
类名:
OvershootInterpolator
资源 id:
@android:anim/overshoot_interpolator
标签名:
overshootInterpolator
数学公式:
y = (T + 1) × (t - 1) + T × (t - 1) + 1
类构造函数:
public OvershootInterpolator(float tension)
参数:
名称:T
属性:android:tension
描述:越界数量值,默认值为 2。
值越大,越界越多,运动也越快
Overshoot Interpolator
类名:
AnticipateOvershootInterpolator
资源 id:
@android:anim/anticipate_overshoot_interpolator
标签名:
anticipateOvershootInterpolator
数学公式:
类构造函数:
- public AnticipateOvershootInterpolator(float tension)
- public AnticipateOvershootInterpolator(float tension, float extraTension)
参数:
属性:android:tension
描述:越界数量值,默认值为 2。
值越大,越界越多,运动也越快
属性:android:extraTension
描述:额外反向张力值,默认值为 1.5。
T 值为:tension * extraTension
Bounce Interpolator(弹性插值器)
类名:
BounceInterpolator
资源 id:
@android:anim/bounce_interpolator
标签名:
bounceInterpolator
数学公式:
类构造函数:
public BounceInterpolator()
参数:
无
* Cycle Interpolator*(弹性插值器)
类名:
Cycle Interpolator
资源 id:
@android:anim/cycle_interpolator
标签名:
cycleInterpolator
数学公式:
y = sin(2π × C × t)
类构造函数:
public CycleInterpolator(float cycles)
参数:
名称:C
属性:android:cycles
描述:循环次数,默认值为 1.
创建新的插值器
正如上面所言,插值器本质上展示的是一个数学公式。要想创建一个属于你自己的插值器类,你必须实现 Interpolator 接口。这个接口只定义了一个方法:
float getInterpolation(float t)
用于公式中的计算。举个例子,我想创建一个名为 HesitateInterpolator 的插值器,动画以最快的速度启动,然后减速运动至一半,最后加速运动至结束。运动曲线如图所示:
对应数学公式为:
HesitateInterpolator 类的代码也很简单:
public class HesitateInterpolator implements Interpolator {
public HesitateInterpolator() {}
public float getInterpolation(float t) {
float x=2.0f*t-1.0f;
return 0.5f*(x*x*x + 1.0f);
}
}
使用这个插值器时,你只需要通过动态编程的方式将其添加到你的 View 动画中去:
ScaleAnimation scale = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f);
scale.setInterpolator(new HesitateInterpolator());
就是这些!不需要任何额外代码。
不幸的事,你不能在 XML 动画资源中使用这个插值器,只支持动态编程的方式。
GIF 图效果
上面所述便是翻译原文的全部部分。最后再附上几张 Gif 图,也来自国外友人的博客,通过对比的形式更加直观地查看不同插值器的作用效果:
- Accelerate Decelerate, Accelerate, Anticipate & Anticipate Overshoot:
- Bounce, Decelerate, Fast Out Linear In & Fast Out Slow In:
- Fast Out Slow In, Linear, Linear Out Slow In & Overshoot