Android属性动画 Interpolator

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/118683683
本文出自【赵彦军的博客】

Interpolator

通俗易懂的说,Interpolator负责控制动画变化的速率,使得基本的动画效果能够以匀速、加速、减速、抛物线速率等各种速率变化。

动画是开发者给定开始和结束的“关键帧”,其变化的“中间帧”是有系统计算决定然后播放出来。因此,动画的每一帧都将在开始和结束之间的特定时间显示。此时动画时间被转换为时间索引,则动画时间轴上的每个点都可以转换成0.0到1.0之间的一个浮点数。然后再将该值用于计算该对象的属性变换。在变换的情况下,y轴上,0.0对应于起始位置,1.0对应于结束位置,0.5对应于起始和结束之间的中间,对于一些插值器其值还可以是0~1之外的数值。

TimeInterpolator

/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

Interpolator

/**
 * An interpolator defines the rate of change of an animation. This allows
 * the basic animation effects (alpha, scale, translate, rotate) to be 
 * accelerated, decelerated, repeated, etc.
 */
public interface Interpolator extends TimeInterpolator {
    // A new interface, TimeInterpolator, was introduced for the new android.animation
    // package. This older Interpolator interface extends TimeInterpolator so that users of
    // the new Animator-based animations can use either the old Interpolator implementations or
    // new classes that implement TimeInterpolator directly.
}

BaseInterpolator

/**
 * An abstract class which is extended by default interpolators.
 */
abstract public class BaseInterpolator implements Interpolator {
    private @Config int mChangingConfiguration;
    /**
     * @hide
     */
    public @Config int getChangingConfiguration() {
        return mChangingConfiguration;
    }

    /**
     * @hide
     */
    void setChangingConfiguration(@Config int changingConfiguration) {
        mChangingConfiguration = changingConfiguration;
    }
}

动画分类

java类xml资源id
AccelerateDecelerateInterpolator@android:anim/accelerate_decelerate_interpolator开始和结束速率较慢,中间加速
AccelerateInterpolator@android:anim/accelerate_interpolator其变化开始速率较慢,后面加速
DecelerateInterpolator@android:anim/decelerate_interpolator开始速率较快,后面减速
LinearInterpolator@android:anim/linear_interpolator速率恒定
AnticipateInterpolator@android:anim/anticipate_interpolator开始向后甩,然后向前
AnticipateOvershootInterpolator@android:anim/anticipate_overshoot_interpolator开始向后甩,然后向前甩,过冲到目标值,最后又回到了终值
OvershootInterpolator@android:anim/overshoot_interpolator开始向前甩,过冲到目标值,最后又回到了终值
BounceInterpolator@android:anim/bounce_interpolator结束时反弹
CycleInterpolator@android:anim/cycle_interpolator循环播放,其速率为正弦曲线

在Android5.0开始,在 android.support.v4.view.animation包下又重新添加这三种插值器

  • FastOutLinearInInterpolator 先加速然后匀速,本质还是加速运动,和Accelerate Interpolator类似
  • LinearOutSlowInInterpolator 先匀速再减速,和Decelerate Interpolator类似
  • FastOutSlowInInterpolator 先加速,然后减速,和Accelerate Decelerate Interpolator类似

BounceInterpolator 反弹动画

在这里插入图片描述


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var button: Button = findViewById(R.id.bt)
        button.animate()
            .translationY(500f)  //y轴向下平移
            .setStartDelay(2000)  //延时2000秒,才开始执行动画
            .setInterpolator(BounceInterpolator())  //设置减速插值器
            .setDuration(1500)   //动画执行时长800毫
    }
}

在这里插入图片描述

CycleInterpolator 循环动画

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var button: Button = findViewById(R.id.bt)
        button.animate()
            .translationY(500f)  //y轴向下平移
            .setStartDelay(2000)  //延时2000秒,才开始执行动画
            .setInterpolator(CycleInterpolator(3f))  //循环动画,执行3次
            .setDuration(1500)   //动画执行时长800毫
    }
}

在这里插入图片描述

OvershootInterpolator 向前甩,越过终点,再回到终点

  • 构造函数: public OvershootInterpolator (float tension)

tension : 张力值,默认为2,T越大,结束时的偏移越大,而且速度越快

在这里插入图片描述

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var button: Button = findViewById(R.id.bt)
        button.animate()
            .translationY(500f)  //y轴向下平移
            .setStartDelay(2000)  //延时2000秒,才开始执行动画
            .setInterpolator(OvershootInterpolator())  //
            .setDuration(1500)   //动画执行时长800毫
    }
}

在这里插入图片描述

AnticipateInterpolator 开始向后甩,然后向前

  • public AnticipateInterpolator(float tension)
  • XML属性: android:tension

张力值, 默认为2,T越大,初始的偏移越大,而且速度越快

在这里插入图片描述

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var button: Button = findViewById(R.id.bt)
        button.animate()
            .translationY(500f)  //y轴向下平移
            .setStartDelay(2000)  //延时2000秒,才开始执行动画
            .setInterpolator(AnticipateInterpolator())  //
            .setDuration(1500)   //动画执行时长800毫
    }
}

在这里插入图片描述

AnticipateOvershootInterpolator 开始向后甩,然后向前甩,过冲到目标值,最后又回到了终值

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var button: Button = findViewById(R.id.bt)
        button.animate()
            .translationY(500f)  //y轴向下平移
            .setStartDelay(2000)  //延时2000秒,才开始执行动画
            .setInterpolator(AnticipateOvershootInterpolator())  //
            .setDuration(1500)   //动画执行时长800毫
    }
}

在这里插入图片描述

AccelerateDecelerateInterpolator 先加速后减速插值器

在这里插入图片描述

DecelerateInterpolator 减速插值器

  • 构造函数: public DecelerateInterpolator(float factor)
  • XML属性: android:factor

加速度参数. f越大,起始速度越快,但是速度越来越慢

在这里插入图片描述

自定义 Interpolator

首先看一下TimeInterpolator的接口定义,代码如下所示:

/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {
 
    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

OK,接口还是非常简单的,只有一个getInterpolation()方法。大家有兴趣可以通过注释来对这个接口进行详解的了解,这里我就简单解释一下,getInterpolation()方法中接收一个input参数,这个参数的值会随着动画的运行而不断变化,不过它的变化是非常有规律的,就是根据设定的动画时长匀速增加,变化范围是01。也就是说当动画一开始的时候input的值是0,到动画结束的时候input的值是1,而中间的值则是随着动画运行的时长在0到1之间变化的。

说到这个input的值,我觉得有不少朋友可能会联想到我们使用过的fraction值。那么这里的inputfraction有什么关系或者区别呢?

答案很简单,input的值决定了fraction的值。input的值是由系统经过计算后传入到getInterpolation()方法中的,然后我们可以自己实现getInterpolation()方法中的算法,根据input的值来计算出一个返回值,而这个返回值就是fraction了。

因此,最简单的情况就是input值和fraction值是相同的,这种情况由于input值是匀速增加的,因而fraction的值也是匀速增加的,所以动画的运动情况也是匀速的。系统中内置的LinearInterpolator就是一种匀速运动的Interpolator,那么我们来看一下它的源码是怎么实现的:

/**
 * An interpolator where the rate of change is constant
 */
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
 
    public LinearInterpolator() {
    }
 
    public LinearInterpolator(Context context, AttributeSet attrs) {
    }
 
    public float getInterpolation(float input) {
        return input;
    }
 
    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}

这里我们只看getInterpolation()方法,这个方法没有任何逻辑,就是把参数中传递的input值直接返回了,因此fraction的值就是等于input的值的,这就是匀速运动的Interpolator的实现方式。

当然这是最简单的一种Interpolator的实现了,我们再来看一个稍微复杂一点的。既然现在大家都知道了系统在默认情况下使用的是AccelerateDecelerateInterpolator,那我们就来看一下它的源码吧,如下所示:

/**
 * An interpolator where the rate of change starts and ends slowly but
 * accelerates through the middle.
 * 
 */
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }
    
    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }
    
    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
 
    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
    }
}

代码虽然没有变长很多,但是getInterpolation()方法中的逻辑已经明显变复杂了,不再是简单地将参数中的input进行返回,而是进行了一个较为复杂的数学运算。

那这里我们来分析一下它的算法实现,可以看到,算法中主要使用了余弦函数,由于input的取值范围是0到1,那么cos函数中的取值范围就是π到2π。而cos(π)的结果是-1,cos(2π)的结果是1,那么这个值再除以2加上0.5之后,getInterpolation()方法最终返回的结果值还是在0到1之间。只不过经过了余弦运算之后,最终的结果不再是匀速增加的了,而是经历了一个先加速后减速的过程。

我们可以将这个算法的执行情况通过曲线图的方式绘制出来,结果如下图所示:

在这里插入图片描述
可以看到,这是一个S型的曲线图,当横坐标从0变化到0.2的时候,纵坐标的变化幅度很小,但是之后就开始明显加速,最后横坐标从0.8变化到1的时候,纵坐标的变化幅度又变得很小。

OK,通过分析LinearInterpolatorAccelerateDecelerateInterpolator的源码,我们已经对Interpolator的内部实现机制有了比较清楚的认识了,那么接下来我们就开始尝试编写一个自定义的Interpolator

编写自定义Interpolator最主要的难度都是在于数学计算方面的,由于我数学并不是很好,因此这里也就写一个简单点的Interpolator来给大家演示一下。既然属性动画默认的Interpolator是先加速后减速的一种方式,这里我们就对它进行一个简单的修改,让它变成先减速后加速的方式。新建DecelerateAccelerateInterpolator类,让它实现TimeInterpolator接口,代码如下所示:

public class DecelerateAccelerateInterpolator implements TimeInterpolator{
 
    @Override
    public float getInterpolation(float input) {
        float result;
        if (input <= 0.5) {
            result = (float) (Math.sin(Math.PI * input)) / 2;
        } else {
            result = (float) (2 - Math.sin(Math.PI * input)) / 2;
        }
        return result;
    }
 
}

这段代码是使用正弦函数来实现先减速后加速的功能的,因为正弦函数初始弧度的变化值非常大,刚好和余弦函数是相反的,而随着弧度的增加,正弦函数的变化值也会逐渐变小,这样也就实现了减速的效果。当弧度大于π/2之后,整个过程相反了过来,现在正弦函数的弧度变化值非常小,渐渐随着弧度继续增加,变化值越来越大,弧度到π时结束,这样从0过度到π,也就实现了先减速后加速的效果。

同样我们可以将这个算法的执行情况通过曲线图的方式绘制出来,结果如下图所示:
在这里插入图片描述

可以看到,这也是一个S型的曲线图,只不过曲线的方向和刚才是相反的。从上图中我们可以很清楚地看出来,一开始纵坐标的变化幅度很大,然后逐渐变小,横坐标到0.5的时候纵坐标变化幅度趋近于零,之后随着横坐标继续增加纵坐标的变化幅度又开始变大,的确是先减速后加速的效果。

看看效果:

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值