Android 动画补间器 Interpolator

Interpolator 用来控制动画的变化速度,可以理解成动画渲染器

其实在讲补间动画的时候我们就提到过补间器 (Interpolator),所有的补间器 (Interpolator) 都继承自 TimeInterpolator

Android 已经为我们提供了好多个动画补间器实现类

说明
LinearInterpolator 动画以均匀的速度改变
AccelerateInterpolator 在动画开始的地方改变速度较慢,然后开始加速
AccelerateDecelerateInterpolator 在动画开始、结束的地方改变速度较慢,中间时加速
AnticipateInterpolator 反向,先按反方向改变一段距离然后加速
AnticipateOvershootInterpolator 开始的时候反向,然后快速向前甩出一段距离然后缓缓回到目的地
BaseInterpolator Interpolator 的基本实现类
BounceInterpolator 跳跃,快结束时值会跳跃,如果目的值是 100,后面的可能值会 88 77 70 95 100
CycleInterpolator 动画循环播放特定次数,变化速度按正弦曲线改变
DecelerateInterpolator 在动画开始的地方变化较快,后面逐渐减低速度
OvershootInterpolator 回弹,在超出目标值会回弹,然后会缓缓回到目标值
PathInterpolator 贝赛尔曲线速度

Interpolator 在 XML 中的使用

上面这些补间器,我们都可以在 XML 中使用,属性是 android:interpolator 而上面的对应值是 @android:anim/linear_interpolator,其实就是驼峰命名法变成下划线,所以 AccelerateInterpolator 对应的就是 @android:anim/accelerate_interpolator

范例

我们先来看看几个补间器的效果

AccelerateInterpolator

使用方式 setInterpolator(new AccelerateInterpolator(2f)) 括号里的值用于控制加速度


  1. 创建一个 空的 Android 项目 cn.twle.android.InterpolatorDemo

  2. 修改 activity_main.xml 添加一个 <Button>

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/ms_layout"
        android:orientation="vertical" >
    
        <TextView
            android:id="@+id/ms_textview"
            android:background="#ff0000"
            android:layout_width="64dp"
            android:layout_height="64dp"/>
    </LinearLayout>
    
  3. 修改 MainActivity.java

    package cn.twle.android.interpolatordemo;
    
    import android.animation.ValueAnimator;
    import android.support.v7.app.AppCompatActivity;
    import android.view.animation.AccelerateInterpolator;
    import android.view.animation.BounceInterpolator;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        TextView ms_textview;
    
        float scale;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            scale = MainActivity.this.getResources().getDisplayMetrics().density;
    
            ms_textview = findViewById(R.id.ms_textview);
    
            final int y = ms_textview.getTop();
    
            ValueAnimator xValue = ValueAnimator.ofInt(0,1000);
    
            xValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int cur = (int) animation.getAnimatedValue();
    
                    ms_textview.layout(
                            0,
                            y+ cur,
                            dp2px(64),
                            y+cur+dp2px(64)
                    );
    
                }
            });
    
            xValue.setDuration(3000L);
            xValue.setInterpolator(new AccelerateInterpolator(2f));
            xValue.start();
        }
    
        public  int dp2px(float dpValue){
    
            return (int)(dpValue* scale+0.5f);
        }
    
    }
    

如果需要有回弹效果,可以把

xValue.setInterpolator(new AccelerateInterpolator(2f));

改成

xValue.setInterpolator(new BounceInterpolator());


Interpolator 内部实现机制

我们先看看 TimeInterpolator 接口的源码,它只定义了 getInterpolation() 方法

/**
 * 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);
}

getInterpolation() 方法中接收一个 input 参数,这个参数的值会随着动画的运行而不断变化

input 的变化是非常有规律的,就是根据设定的动画时长匀速增加,变化范围是 0 到 1

也就是说当动画一开始的时候 input 的值是 0,到动画结束的时候 input 的值是 1,而中间的值则 是随着动画运行的时长在 0 到 1 之间变化的

input 值决定了我们 TypeEvaluator 接口里的 fraction 的值

input 的值是由系统经过计算后传入到 getInterpolation() 方法中的,如果可以自己实现 getInterpolation() 方法中的算法,根据 input 的值来计算出一个返回值,而这个返回值就是 fraction

LinearInterpolator

我们可以看看 LinearInterpolator 里的代码

public float getInterpolation(float input) {
    return input;
}

这里没有处理过直接返回 input 值,即 fraction 的值就是等于 input 的值,这就是匀速运动的 Interpolator的实现方式

BounceInterpolator

private static float bounce(float t) {
    return t * t * 8.0f;
}

public float getInterpolation(float t) {

    t *= 1.1226f;
    if (t < 0.3535f) return bounce(t);
    else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
    else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
    else return bounce(t - 1.0435f) + 0.95f;
}

AccelerateDecelerateInterpolator

public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

这个Interpolator 是先加速后减速效果的 (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f

input 的取值范围为 [0,1] ,可以得出 cos 中的值的取值范围为 [π,2π],对应的值为 -11

再用这个值来除以 2 加上 0.5 之后,getInterpolation() 方法最终返回的结果值范围还是[0,1], 对应的曲线图如下

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.