Android-贝塞尔插值器的使用

1,765 阅读4分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

目录

什么是Interpolator?

通俗易懂的说,Interpolator(插值器)负责控制动画变化的速率,使得基本的动画效果能够以匀速、加速、减速、抛物线速率等各种速率变化。
入口:Android 属性动画(Property Animation) 使用详解
入口:android动画——属性动画(Property Animation)
在动画开发过程中,经常需要使用到插值器来满足我们的动画设计需求。然而,官方提供的插值器并不能满足所有的需求,所以我们需要自定义插值器。

官方提供的插值器有哪些呢?

官方内置了9钟插值器:LinearInterpolator(线性插值器:匀速)、AccelerateInterpolator(加速度插值器: 起始速度慢,然后越来越快)、DecelerateInterpolator(减速插值器:起始速度快,然后越来越慢)等等。
在这里插入图片描述

想要详细了解官方提供的插值器,可以去看以下几位老兄的博客。
再谈属性动画——介绍以及自定义Interpolator插值器
Android 属性动画 常用方法 与 插值器 Interpolator
android 动画系列 (2) - interpolator 插值器
几种常用的Interpolator(插值器)的动画效果
这边只简单搬运一下前四个:

1.Linear Interpolator / 线性插值器

公式: y=kt
(1)任何物理量对时间的导数都是该物理量随时间的变化率。位移对时间的导数是速度,而速度对时间的导数是加速度。
(2)函数y=f(x)在x0点的导数f’(x0)的几何意义:表示函数曲线在点P0(x0,f(x0))处的切线的斜率(导数的几何意义是该函数曲线在这一点上的切线斜率)。

根据上述可知,你可以直接求导,斜率=k,且始终保持不变,匀速行驶。
也可以观测图像在每一点的切线的斜率。
在这里插入图片描述

2.Accelerate Interpolator / 加速度插值器

公式: y=t^(2f)描述: 加速度参数. f越大,起始速度越慢,但是速度越来越快。

在这里插入图片描述

3.Decelerate Interpolator / 减速插值器

公式: y=1-(1-t)^(2f)描述: 加速度参数. f越大,起始速度越快,但是速度越来越慢
在这里插入图片描述

4.Accelerate Decelerate Interpolator / 先加速后减速插值器

公式: y=cos((t+1)π)/2+0.5
在这里插入图片描述

官方插值器AccelerateDecelerate Interpolator的验证

1.代码

        ValueAnimator mAnimator = ValueAnimator.ofFloat(1.0f, 5.0f).setDuration(800);
        mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.e("Rachel_test", "controlLeft: " + animation.getAnimatedValue());
            }
        });
        mAnimator.start();

2.ctrl+alt复制数据

在这里插入图片描述

1.0
1.0
1.0772363
1.1739753
1.2324686
1.3029796
1.3819662
1.4690335
1.5582927
1.6597944
1.7679892
1.8758329
1.9954689
2.1201217
2.249169
2.3745017
2.5102313
2.6484075
2.7805316
2.9214802
3.0628214
3.203849
3.3361187
3.4745245
3.6105597
3.7362492
3.8657446
3.9909172
4.1111403
4.219599
4.328505
4.430776
4.520812
4.6087513
4.688656
4.7601266
4.8195605
4.8736496
4.9183817
4.9518337
4.9777727
4.9938345
4.9999385
5.0

3.拷贝数据到excel

=A2-A1
在这里插入图片描述

4.结果

很明显可以看出来,这是一个加速后又减速的插值器
在这里插入图片描述

实践:项目背景

UI小姐姐让实现一个类似于下面动图的动画。
在这里插入图片描述
动画变化的速率要求如下所示,显然有明确要求的变化速率无法使用官方提供的插值器。
PCR动画说明
在这里插入图片描述

绘制满足设计的动画曲线

基于三次方贝塞尔曲线的插值器

public class AnimationActivity extends Activity {

   ........
    /**
     * 组合动画
     */
    private void bine() {
        //welcomeTv
        PropertyValuesHolder welcomeTv_1 = PropertyValuesHolder.ofFloat("scaleX", 0.98f, 1f);
        PropertyValuesHolder welcomeTv_2 = PropertyValuesHolder.ofFloat("scaleY", 0.98f, 1f);
        ObjectAnimator welcomeAnimator1 = ObjectAnimator.ofPropertyValuesHolder(welcomeTv, welcomeTv_1, welcomeTv_2);
        //设置自定义插值器
        welcomeAnimator1.setInterpolator(new EaseCubicInterpolator(0.33f, 0f, 0.67f, 1f));
        welcomeAnimator1.setDuration(1100);

        ValueAnimator welcomeAnimator2 = ObjectAnimator.ofFloat(this.welcomeTv, "alpha", 0f, 1f);
        welcomeAnimator2.setInterpolator(new EaseCubicInterpolator(0.63f, 0f, 0.76f, 1f));
        welcomeAnimator2.setDuration(1100);

        //pcrTv
        ValueAnimator pcrAnimator = ObjectAnimator.ofFloat(this.pcrTv, "alpha", 0f, 1f);
        pcrAnimator.setInterpolator(new EaseCubicInterpolator(0.76f, 0f, 0.8f, 1f));
        pcrAnimator.setDuration(500);
        pcrAnimator.setStartDelay(1100);
        //blueImg
        ValueAnimator blueAnimator = ObjectAnimator.ofFloat(this.blueImg, "alpha", 0f, 1f);
        blueAnimator.setInterpolator(new EaseCubicInterpolator(0.76f, 0f, 0.8f, 1f));
        blueAnimator.setDuration(500);
        blueAnimator.setStartDelay(1200);
        //grayImg

        ValueAnimator grayAnimator1 = ObjectAnimator.ofFloat(this.grayImg, "alpha", 0f, 1f);
        grayAnimator1.setInterpolator(new EaseCubicInterpolator(0.6f, 0f, 0.52f, 1f));
        grayAnimator1.setDuration(1100);
        grayAnimator1.setStartDelay(1000);

        ValueAnimator grayAnimator2 = ObjectAnimator.ofFloat(this.grayImg, "rotation", -200f, 0f);
        grayAnimator2.setInterpolator(new LinearInterpolator());
        grayAnimator2.setDuration(1100);
        grayAnimator2.setStartDelay(1000);


        AnimatorSet animSet = new AnimatorSet();
        animSet.play(welcomeAnimator1).with(welcomeAnimator2).with(pcrAnimator).with(blueAnimator).with(grayAnimator1).with(grayAnimator2);
        animSet.start();
    }
}


/**
 * 缓动三次方曲线插值器.(基于三次方贝塞尔曲线)
 */

public class EaseCubicInterpolator implements Interpolator {


    private final static int ACCURACY = 4096;

    private int mLastI = 0;

    private final PointF mControlPoint1 = new PointF();

    private final PointF mControlPoint2 = new PointF();


    /**
     * 设置中间两个控制点.<br>
     * <p>
     * 在线工具: http://cubic-bezier.com/<br>
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     */

    public EaseCubicInterpolator(float x1, float y1, float x2, float y2) {

        mControlPoint1.x = x1;

        mControlPoint1.y = y1;

        mControlPoint2.x = x2;

        mControlPoint2.y = y2;

    }


    @Override

    public float getInterpolation(float input) {

        float t = input;

        // 近似求解t的值[0,1]

        for (int i = mLastI; i < ACCURACY; i++) {

            t = 1.0f * i / ACCURACY;

            double x = cubicCurves(t, 0, mControlPoint1.x, mControlPoint2.x, 1);

            if (x >= input) {

                mLastI = i;

                break;

            }

        }

        double value = cubicCurves(t, 0, mControlPoint1.y, mControlPoint2.y, 1);

        if (value > 0.999d) {

            value = 1;

            mLastI = 0;

        }

        return (float) value;

    }


    /**
     * 求三次贝塞尔曲线(四个控制点)一个点某个维度的值.<br>
     * <p>
     * 参考资料: <em> http://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/ </em>
     *
     * @param t      取值[0, 1]
     * @param value0
     * @param value1
     * @param value2
     * @param value3
     * @return
     */

    public static double cubicCurves(double t, double value0, double value1,

                                     double value2, double value3) {

        double value;

        double u = 1 - t;

        double tt = t * t;

        double uu = u * u;

        double uuu = uu * u;

        double ttt = tt * t;


        value = uuu * value0;

        value += 3 * uu * t * value1;

        value += 3 * u * tt * value2;

        value += ttt * value3;

        return value;

    }

}



<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:background="#FFF4F5F9"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/welcome_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="384dp"
        android:layout_marginLeft="384dp"
        android:layout_marginTop="310dp"
        android:text="Welcome to"
        android:textColor="#ff333333"
        android:textSize="40sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:alpha="0"
        android:id="@+id/pcr_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:text="Real-time PCR System"
        android:textColor="#80666666"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="@id/welcome_tv"
        app:layout_constraintTop_toBottomOf="@id/welcome_tv" />

    <ImageView
        android:alpha="0"
        android:id="@+id/blue_img"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="628dp"
        android:layout_marginTop="278dp"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@mipmap/circle_blue" />

    <ImageView
        android:id="@+id/gray_img"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="484dp"
        android:layout_marginTop="260dp"
        android:layout_width="190dp"
        android:alpha="0"
        android:layout_height="190dp"
        android:src="@mipmap/circle_grey" />
</android.support.constraint.ConstraintLayout>

Java基础不好的小水怪,正在学习。有错请指出,一起加油。