023-Android动画(3):插值器与估值器详解

2,956 阅读3分钟

1.简述

Android有三种动画,分别是视图动画属性动画,帧动画。

其中,帧动画因为资源占用大、性能差、内存溢出等不足,实际开发不推荐使用。

2. 插值器 Interpolator

类似物理中的加速度,定义动画进度值变化的速度,默认为线性变化。

android中定义的插值器:

插值器功能
AccelerateDecelerateInterpolator先加速,后减速
LinearInterpolator默认线性,匀速变化,无实际使用
AccelerateInterpolator加速运行至结束
DecelerateInterpolator减速运行至结束
OvershootInterpolator越界折返
AnticipateInterpolator先后退一小步再加速
AnticipateOvershootInterpolator先后退一小步再加速,超出终点一小部分后再折回
BounceInterpolator弹性插值器,篮球落地回弹效果
CycleInterpolator周期循环

2.1 自定义插值器

通常自定义插值器需实现Interceptor接口

1. 属性动画用的插值器需实现TimeInterpolator接口;
2. 补间动画用的插值器需实现Interpolator
3. Interpolator继承了TimeInterceptor

接口

//input表示进度值0%-100%
public interface TimeInterpolator {
 float getInterpolation(float input);
}

public interface Interpolator extends TimeInterpolator {
}

1.自定义插值器

package com.cupster.animation;
import android.view.animation.Interpolator;
class SinInterpolater implements Interpolator {
    @Override
    public float getInterpolation(float input) {
        input = input -0.5f;
        return (float)Math.sin(60*input) + 0.5f;
    }
}

2.封装使用方法

 public static void myAnim(View target ,float... transx){
        ObjectAnimator animator = ObjectAnimator.ofFloat(target ,"translationX",transx);
        animator.setDuration(3000);
        animator.setInterpolator(new SinInterpolater());
        animator.start();
    }

3.使用

        img = findViewById(R.id.anim_view);
        img.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PropAnimatorHelper.myAnim(view ,0,10,0,10);//点击后左右抖动
            }
        });

4.效果:点击后左右抖动

3.估值器 TypeEvaluator

估值器是定义动画进度值的取值规则。

系统默认的FloatEvaluator、IntEvaluator都是根据进度值自然线性递增。

public class FloatEvaluator implements TypeEvaluator<Number> {

    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}

举例:0-100的取值范围,就是1,2,3,4,...,99,100

根据使用场景,我们可以自定义估值器,获得如: 0,3,6,9,...,96,99

3.1 自定义估值器

TypeEvaluator接口

public interface TypeEvaluator<T> {
                //fraction进度值
    public T evaluate(float fraction, T startValue, T endValue);
}

1.自定义估值器

package com.cupster.animation;

import android.animation.TypeEvaluator;

/**
 * 此处代码为郭霖大神编写的自定义Evaluator,用于扩展属性动画:"color",
 * 使用该动画的View需设置对应public void setColor,并在其中调用invalidate()
 */
public class ColorEvaluator implements TypeEvaluator {

    private int mCurrentRed = -1;

    private int mCurrentGreen = -1;

    private int mCurrentBlue = -1;

    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        String startColor = (String) startValue;
        String endColor = (String) endValue;
        int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
        int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
        int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);
        int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
        int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
        int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);
        // 初始化颜色的值
        if (mCurrentRed == -1) {
            mCurrentRed = startRed;
        }
        if (mCurrentGreen == -1) {
            mCurrentGreen = startGreen;
        }
        if (mCurrentBlue == -1) {
            mCurrentBlue = startBlue;
        }
        // 计算初始颜色和结束颜色之间的差值
        int redDiff = Math.abs(startRed - endRed);
        int greenDiff = Math.abs(startGreen - endGreen);
        int blueDiff = Math.abs(startBlue - endBlue);
        int colorDiff = redDiff + greenDiff + blueDiff;
        if (mCurrentRed != endRed) {
            mCurrentRed = getCurrentColor(startRed, endRed, colorDiff, 0,
                    fraction);
        } else if (mCurrentGreen != endGreen) {
            mCurrentGreen = getCurrentColor(startGreen, endGreen, colorDiff,
                    redDiff, fraction);
        } else if (mCurrentBlue != endBlue) {
            mCurrentBlue = getCurrentColor(startBlue, endBlue, colorDiff,
                    redDiff + greenDiff, fraction);
        }
        // 将计算出的当前颜色的值组装返回
        String currentColor = "#" + getHexString(mCurrentRed)
                + getHexString(mCurrentGreen) + getHexString(mCurrentBlue);
        return currentColor;
    }

    /**
     * 根据fraction值来计算当前的颜色。
     */
    private int getCurrentColor(int startColor, int endColor, int colorDiff,
                                int offset, float fraction) {
        int currentColor;
        if (startColor > endColor) {
            currentColor = (int) (startColor - (fraction * colorDiff - offset));
            if (currentColor < endColor) {
                currentColor = endColor;
            }
        } else {
            currentColor = (int) (startColor + (fraction * colorDiff - offset));
            if (currentColor > endColor) {
                currentColor = endColor;
            }
        }
        return currentColor;
    }

    /**
     * 将10进制颜色值转换成16进制。
     */
    private String getHexString(int value) {
        String hexString = Integer.toHexString(value);
        if (hexString.length() == 1) {
            hexString = "0" + hexString;
        }
        return hexString;
    }

}

2.封装方法

   public static void propColorAnimator(ColorTextView target , String startColor , String endColor){
        ObjectAnimator animator = ObjectAnimator.ofObject(target ,"color",new ColorEvaluator() ,startColor,endColor);
        animator.setDuration(3000);
        animator.start();
    }

3.扩展View

class ColorTextView extends TextView {

    public void setColor(String color){
        setTextColor(Color.parseColor(color));
    }

    public ColorTextView(Context context) {
        super(context);
    }

    public ColorTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

}

4.使用

        img = findViewById(R.id.anim_view);
        img.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PropAnimatorHelper.propColorAnimator((ColorTextView) view,"#a7dbf7" ,"#ff8696");
            }
        });