Android動畫系列之插值器、估計器

1 前言
前兩篇分別介紹了View動畫及幀動畫、屬性動畫的基本用法,多多少少提到了TypeEvaluator(類型估值器)、Interpolator(插值器),但并沒有展開介紹,主要是因為View動畫、屬性動畫的常見的基本用法,系統(tǒng)源碼內(nèi)部已經(jīng)默認使用了某種估值器和插值器。本文先介紹系統(tǒng)提供的了哪些TypeEvaluator和Interpolator?然后介紹如何自定義一個TypeEvaluator和Interpolator來實例演示。
2 TypeEvaluator(類型估值器)
TypeEvaluator用于計算從初始值過度到結(jié)束值時某個時刻的取值 ,與屬性的起始值,結(jié)束值,fraction三個值相關(guān),也就是ValueAnimator.getAnimatedValue()返回的值。
首先,看看TypeEvaluator源碼:

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

TypeEvaluator是一個接口,接口采用泛型,因此,無論是系統(tǒng)預(yù)置的估值器還是自定義估值器都是實現(xiàn)該接口。evaluate方法有三個參數(shù),其中startValue和endValue很好理解就是初始值和結(jié)束值,而fraction是經(jīng)過插值器轉(zhuǎn)換后的值,插值器下節(jié)再介紹,系統(tǒng)內(nèi)置的估值器有:
IntEvaluator Int類型估值器,ofInt()方法系統(tǒng)默認使用的估值器,
FloatEvaluator Float類型估值器,ofFloat()方法系統(tǒng)默認使用的估值器,
ArgbEvaluator 顏色類型估值器,ofArgb()方法系統(tǒng)默認使用的估值器 。

IntEvaluator源碼

public class IntEvaluator implements TypeEvaluator<Integer> {

    /**
     * <code>result = x0 + t * (v1 - v0)</code>,
     */
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

FloatEvaluator源碼

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

ArgbEvaluator源碼

public class ArgbEvaluator implements TypeEvaluator {
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        float startA = ((startInt >> 24) & 0xff) / 255.0f;
        float startR = ((startInt >> 16) & 0xff) / 255.0f;
        float startG = ((startInt >>  8) & 0xff) / 255.0f;
        float startB = ( startInt        & 0xff) / 255.0f;

        int endInt = (Integer) endValue;
        float endA = ((endInt >> 24) & 0xff) / 255.0f;
        float endR = ((endInt >> 16) & 0xff) / 255.0f;
        float endG = ((endInt >>  8) & 0xff) / 255.0f;
        float endB = ( endInt        & 0xff) / 255.0f;

        // convert from sRGB to linear
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);

        // compute the interpolated color in linear space
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // convert back to sRGB in the [0..255] range
        a = a * 255.0f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

        return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
    }
}

以上三種系統(tǒng)內(nèi)置的估算器均是通過公式result = x0 + t * (v1 - v0)計算返回。其中ArgbEvaluator是分別對ARGB四個分量分別計算然后組裝返回。
下面通過自定義實現(xiàn)類似拋物線運動的軌跡的動畫效果。先給出效果圖:


3.gif

首先先自定一個MyEvaluator實現(xiàn)TypeEvaluator接口,代碼如下:

/**
 * @Description 自定義估值器實現(xiàn)類似拋物線效果
 * @Author Jason.chen
 * @Version
 */

public class MyEvaluator implements TypeEvaluator<PointF> {

    /**
     * 拋物線標準方程:y = a * x^2
     * 假設(shè)x方向速度為100px/s,那么x = 100 * t (t表示時間 由于fraction = t/duration,所以 t = fraction * duration),
     * 再假設(shè)a取為0.5 那么y = 0.5 * x^2
     */
    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        PointF point = new PointF();
        float time = fraction * 5;//設(shè)置duration = 5000ms
        point.x = 100 * time;
        point.y =  0.5f * 100 * time * time;
        return point;
    }
}

然后使用ValueAnimator在監(jiān)聽器中動態(tài)改變img的x,y,就可以實現(xiàn)上述動效。

ValueAnimator valueAnimator =ValueAnimator.ofObject(new MyEvaluator(),new PointF(0,0));
        valueAnimator.setDuration(5000);
        valueAnimator.setInterpolator(new LinearInterpolator());//使用線性插值器
        valueAnimator.start();
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF currentValue = (PointF)  animation.getAnimatedValue();
                Log.i("Tag","current value:"+animation.getAnimatedValue());
                img.setX(currentValue.x);
                img.setY(currentValue.y);
            }
        });

3 Interpolator(插值器)
上一節(jié)介紹TypeEvaluator 時,我們提過evaluate方法有個參數(shù)fraction是經(jīng)過插值器轉(zhuǎn)換后的值,那么插值器到底是什么,有什么作用?下面我們就開始介紹。
Interpolator是用來改變動畫的播放速率,采用不用的插值器來實現(xiàn)不同的播放效果,比如上一節(jié)的動畫效果,使用了線性插值器,使動畫勻速改變。系統(tǒng)默認的使用的插值器是AccelerateDecelerateInterpolator(加速減速插值器)。

//系統(tǒng)自帶的所有插值器都繼承了BaseInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }
    //核心方法,定義了插值的映射關(guān)系
    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();
    }
}

AccelerateDecelerateInterpolator繼承BaseInterpolator類,那么打開BaseInterpolator看下

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;
    }
}

BaseInterpolator是個抽象類,實現(xiàn)了Interpolator接口,Interpolator接口又只是單純地繼承了TimeInterpolator,我們直接TimeInterpolator,TimeInterpolator接口中定義了getInterpolation方法,該方法是計算插值的核心方法,也是自定義插值器要實現(xiàn)的方法。

public interface TimeInterpolator {
  float getInterpolation(float input);
}

系統(tǒng)提供了以下插值器,可以通過插值器類源碼的getInterpolation方法概括出該插值器的公式形式:

資源ID 公式 含義
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator y = 0.5cos((t+1)π)+0.5 始末速率較慢,中間加速
AccelerateInterpolator @android:anim/accelerate_interpolator y=t^(2f) 其中f表示加速因子默認1 先慢后快加
AnticipateInterpolator @android:anim/anticipate_interpolator y = tt((s+1)t-s) 其中s表示張力因子,默認值為2 開始的時候從后向前甩
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator t < 0.5時,y = 2tt(2t*s+2t-s),當t >= 0.5時y = 2(t-1)(t-1)(2(s+1)(t-1)+s) + 1 其中s表示張力因子,默認值為3 開始的時候向后然后向前甩一定值后返回最后的值
BounceInterpolator @android:anim/bounce_interpolator 動畫結(jié)束時彈起
CycleInterpolator @android:anim/cycle_interpolator y = sin(2ct*π)其中c表示循環(huán)次數(shù)默認為1 循環(huán)播放速率播放特定次數(shù),改變?yōu)檎仪€
DecelerateInterpolator @android:anim/decelerate_interpolator y = y= 1-(1-t)^(2f) f為減速因子, 默認值為1 先快后慢
LinearInterpolator @android:anim/linear_interpolator y = t 勻速改變
OvershootInterpolator @android:anim/overshoot_interpolator y = (t-1)(t-1)((s+1)(t-1)+s) + 1 其中s表示張力因子,默認值為2 向前甩一定值后再回到原來位置
PathInterpolator 定義路徑坐標,然后可以按照路徑坐標來跑動

系統(tǒng)已經(jīng)提供了比較全的插值器,本文就不再自定義插值器,主要是沒想到比較好的自定義插值器類型。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容