Android 动画:插值器与估值器

1、插值器(Interpolator)

1.1、简介

  • 定义:一个接口
  • 作用: 设置属性值从初始值过滤到结束值的变化规律,即确定了动画的变化模式
    例如:匀减速,匀加速,先减速后加速,先加速后减速,匀速等等。

1.2、应用举例

实现非线性运动的动画效果(动画的速率不是一成不变的,可能有加速、减速)

1.3、具体使用

插值器在动画中的设置方式有两种:Java 代码中设置和XML文件中设置
1、在XML中设置



2、在Java代码中设置

             //1.创建透明动画对象
                Animation animation = new AlphaAnimation(1, 0);
                //2.创建插值器
                Interpolator interpolator = new OvershootInterpolator();
                //3.给动画设置插值器
                animation.setInterpolator(interpolator);
                //4.播放动画
                ivOne.startAnimation(animation);

以上我们用到了OvershootInterpolator这个系统的插值 器,那其实系统内置9种插值器的实现,我们通过表格的形式列出来。


Android 动画:插值器与估值器_第1张图片
image.png

1.4、自定义插值器

以上我们介绍了插值器的如何使用以及系统内置的9中插值器,其实系统的插值器已经基本可以满足我们平常的开发使用。但是有时候我们需要做到的效果系统的插值器无法实现,我们也可以自定义插值器。

  • 具体实现
    自定义插值器需要实现 Interpolator / TimeInterpolator接口 & 复写getInterpolation()
    (1)补间动画 实现 Interpolator接口;属性动画实现TimeInterpolator接口
    (2)TimeInterpolator接口是属性动画中新增的,用于兼容Interpolator接口,这使得所有过去的Interpolator实现类都可以直接在属性动画使用
  • 实例
    自定义一个Interpolator,先减速后加速
    1、创建MyInterpolator类,实现TimeInterpolator接口,最核心的部分就是通过改变getInterpolation返回值的变化来设置为先减速后加速。
package com.example.administrator.workmanager;

import android.animation.TimeInterpolator;

/**
 * weishixiong
 * 2019/4/23
 */
public class MyInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        float result;
        //动画前半部分
        if(input<=0.5){
            result = (float) (Math.sin(Math.PI * input)) / 2;
            // 使用正弦函数来实现先减速后加速的功能,逻辑如下:
            // 因为正弦函数初始弧度变化值非常大,刚好和余弦函数是相反的
            // 随着弧度的增加,正弦函数的变化值也会逐渐变小,这样也就实现了减速的效果。
            // 当弧度大于π/2之后,整个过程相反了过来,现在正弦函数的弧度变化值非常小,
            // 渐渐随着弧度继续增加,变化值越来越大,弧度到π时结束,这样从0过度到π,也就实现了先减速后加速的效果
        }
        else{
            result = (float) (2 - Math.sin(Math.PI * input)) / 2;
        }

        return result;
    }
}

2、给属性动画设置插值器,View执行属性动画

               //获得当前图片的位置
                float curTranslationX = ivOne.getTranslationX();
                // 创建动画对象 & 设置动画
                // 表示的是:
                // 动画作用对象是ivOne
                // 动画作用的对象的属性是X轴平移
                // 动画效果是:从当前位置平移到 x=300 再平移到初始位置
                ObjectAnimator animator = ObjectAnimator.ofFloat(ivOne, "translationX", curTranslationX, 300,curTranslationX);
                animator.setDuration(5000);
                //  // 设置插值器
                animator.setInterpolator(new MyInterpolator());
                // 启动动画
                animator.start();

以上我们就完成了一个自定义的插值器,并通过属性动画进行设置,然后执行动画。

2、估值器(TypeEvaluator)

2.1、简介

  • 定义:一个接口
  • 作用: 设置属性值从初始值过度到最终值的具体变化数值。
    (1)插值器决定的是动画具体的变化规律
    (2)估值器指的是在某个变化规律上具体的变化数值,比如动画的加速具体的数值。

2.2、应用场景

配合插值器完成非线性的动画效果

2.3、具体实现

ObjectAnimator anim = ObjectAnimator.ofObject(myView2, "height", new IntEvaluator(),1,3);

设置一个View的高从1变化到3的效果,在第4个参数中传入对应估值器类的对象,IntEvaluator指的是以整型的形式从初始值 - 结束值 进行过渡。
系统内置的估值器有3个:

  • IntEvaluator:以整型的形式从初始值 - 结束值 进行过渡
  • FloatEvaluator:以浮点型的形式从初始值 - 结束值 进行过渡
  • ArgbEvaluator:以Argb类型的形式从初始值 - 结束值 进行过渡

2.4、自定义估值器

如果以上系统内置的估值器无法满足开发的需求,我们可以自定义估值器。

  • 实例
    自定义一个估值器,作用在一个圆上,通过改变圆心的坐标,来实现动画效果。
    1、创建圆心实体类Point.java
package com.example.administrator.workmanager;

/**
 * 圆心实体类
 */
public class Point {

    // 设置两个变量用于记录坐标的位置
    private float x;
    private float y;

    // 构造方法用于设置坐标
    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    // get方法用于获取坐标
    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }
}

2、实现TypeEvaluator接口,自定义估值器

package com.example.administrator.workmanager;

import android.animation.TypeEvaluator;

// 实现TypeEvaluator接口
public class PointEvaluator implements TypeEvaluator {

    /**
     *
     * @param fraction 插值器getInterpolation()的返回值  可以理解为动画进行进度的百分比。
     *                 当进度为100%的时候,即动画完成了
     * @param startValue 动画的初始值
     * @param endValue 动画的结束值
     * @return
     */
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {

        // 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;

        // 根据fraction(动画进行的百分比)来计算当前动画的x和y的值
        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
        float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
        
        // 将计算后的坐标封装到一个新的Point对象中并返回
        Point point = new Point(x, y);
        return point;
    }

}

3、将属性动画作用到自定义View当中

package com.example.administrator.workmanager;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * weishixiong
 */
public class MyView extends View {
    // 设置需要用到的变量
    public static final float RADIUS = 70f;// 圆的半径 = 70
    private Point currentPoint;// 当前点坐标
    private Paint mPaint;// 绘图画笔
    

    // 构造方法(初始化画笔)
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 初始化画笔
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

    // 复写onDraw()从而实现绘制逻辑
    // 绘制逻辑:先在初始点画圆,通过监听当前坐标值(currentPoint)的变化,每次变化都调用onDraw()重新绘制圆,从而实现圆的平移动画效果
    @Override
    protected void onDraw(Canvas canvas) {
        // 如果当前点坐标为空(即第一次)
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            // 创建一个点对象(坐标是(70,70))

            // 在该点画一个圆:圆心 = (70,70),半径 = 70
            float x = currentPoint.getX();
            float y = currentPoint.getY();
            canvas.drawCircle(x, y, RADIUS, mPaint);


 // (重点关注)将属性动画作用到View中
            // 步骤1:创建初始动画时的对象点  & 结束动画时的对象点
            Point startPoint = new Point(RADIUS, RADIUS);// 初始点为圆心(70,70)
            Point endPoint = new Point(700, 1000);// 结束点为(700,1000)

            // 步骤2:创建动画对象 & 设置初始值 和 结束值
            ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
            // 参数说明
            // 参数1:TypeEvaluator 类型参数 - 使用自定义的PointEvaluator(实现了TypeEvaluator接口)
            // 参数2:初始动画的对象点
            // 参数3:结束动画的对象点

            // 步骤3:设置动画参数
            anim.setDuration(5000);
            // 设置动画时长

// 步骤3:通过 值 的更新监听器,将改变的对象手动赋值给当前对象
// 此处是将 改变后的坐标值对象 赋给 当前的坐标值对象
            // 设置 值的更新监听器
            // 即每当坐标值(Point对象)更新一次,该方法就会被调用一次
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    currentPoint = (Point) animation.getAnimatedValue();
                    // 将每次变化后的坐标值(估值器PointEvaluator中evaluate()返回的Piont对象值)到当前坐标值对象(currentPoint)
                    // 从而更新当前坐标值(currentPoint)

                    // 步骤4:每次赋值后就重新绘制,从而实现动画效果
                    invalidate();
                    // 调用invalidate()后,就会刷新View,即才能看到重新绘制的界面,即onDraw()会被重新调用一次
                    // 所以坐标值每改变一次,就会调用onDraw()一次
                }
            });

            anim.start();
            // 启动动画


        } else {
            // 如果坐标值不为0,则画圆
            // 所以坐标值每改变一次,就会调用onDraw()一次,就会画一次圆,从而实现动画效果

            // 在该点画一个圆:圆心 = (30,30),半径 = 30
            float x = currentPoint.getX();
            float y = currentPoint.getY();
            canvas.drawCircle(x, y, RADIUS, mPaint);
        }
    }


}

4、在布局文件加入自定义View空间


已经我们就完成了一个圆,通过自定义估值器,改变圆心坐标,完成圆类似抛物线的效果。

3、小结

插值器和估值器主要是为了实现一些复杂效果而产生,插值器确定的是动画的变化规律,估值器确定的是动画变化的具体数值。系统中内置有了常用的插值器和估值器,假如在开发中系统内置的不能满足我们的需求,我们也可以自定义插值器和估值器。

你可能感兴趣的:(Android 动画:插值器与估值器)