1. 程式人生 > >屬性動畫2:ValueAnimator高階進階(一)

屬性動畫2:ValueAnimator高階進階(一)

1. 概述

前面一篇屬性動畫1:基礎知識和ValueAnimator寫完,我對屬性動畫基礎知識和ValueAnimator的簡單用法有了一些瞭解。要想把屬性動畫吃透,我感覺需要更加深入的學習。現在,就從ValueAnimator的高階進階開始,繼續攻克我的屬性動畫。
ValueAnimator的高階進階主要涉及到插值器(Interpolator)和計算器(Evaluator)的使用。

我們知道ValueAnimator是對值的動畫,它在整個動畫持續時間內按一定規則平滑計算出一系列某種型別的中間值。這個規則就可以理解為插值器,對某種型別的值的計算由型別計算器負責。

在上一篇文章中我們已經提到過:

在動畫執行過程中,ValueAnimator根據動畫總時長duration和動畫已經執行的時間,計算出一個在0到1之間的時間流逝小數(elapsed fraction),這個小數(elapsed fraction)表示動畫已經執行的時間百分比,0表示0%,1表示100%。

當ValueAnimator開始計算時間流逝小數(elapsed fraction),它就會呼叫時間插值器TimeInterpolator,插值器內部定義了關於時間(時間流逝小數:elapsed fraction)的函式,這個內部的時間函式通過對時間流逝小數(elapsed fraction)的計算,得到一個插值小數(interpolated fraction)。

計算了插值小數(interpolated fraction),ValueAnimator就會呼叫合適的TypeEvaluator,根據插值小數(interpolated fraction)、開始值和結束值計算出當前的屬性值。

2. 插值器

但到底什麼是插值器?插值器在ValueAnimator中是怎麼使用的呢?時間插值器(TimeInterpolator)顧名思義,它一定與時間有關。事實上插值器就是一個關於時間的函式,它通過對時間流逝小數(或時間流逝百分比)進行一定的函式計算,獲得一個個插值小數,這個小數可以代表動畫值變化(增加或減少)的百分比。說白了就是時間流逝百分比與屬性值變化百分比之間的對應關係,或者函式關係。插值器決定了動畫值隨著時間流逝如何變化,是線性變化(均勻變化)還是非線性變化(如先加速後減速)。

AccelerateDecelerateInterpolator 加速減速插值器
原始碼如下:

/**
 * An interpolator where the rate of change starts and ends slowly but
 * accelerates through the middle.
 */
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }

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

根據getInterpolation()方法可以得出其變化曲線如下:
加速減速插值器函式曲線

原始碼中的getInterpolation()方法的引數input其實就是時間流逝小數。

2.1 簡單原始碼分析

上一篇中,我們知道ValueAnimator預設插值器是加速減速插值器(AccelerateDecelerateInterpolator),從ValueAnimator的原始碼中可以看到:
ValueAnimator預設插值器
如果沒有給動畫設定插值器(加速器)就使用預設插值器。

插播一下,往下翻看ValueAnimator的原始碼發現,
屬性動畫預設duration
屬性動畫預設時長是300ms。

為ValueAnimator設定插值器,需要呼叫ValueAnimator的setInterpolator()方法,下面是ValueAnimator的setInterpolator()方法的原始碼:

/**
 * The time interpolator used in calculating the elapsed fraction of this animation. The
 * interpolator determines whether the animation runs with linear or non-linear motion,
 * such as acceleration and deceleration. The default value is
 * {@link android.view.animation.AccelerateDecelerateInterpolator}
 *
 * @param value the interpolator to be used by this animation. A value of <code>null</code>
 * will result in linear interpolation.
 */
@Override
public void setInterpolator(TimeInterpolator value) {
    if (value != null) {
        mInterpolator = value;
    } else {
        mInterpolator = new LinearInterpolator();
    }
}

setInterpolator()原始碼,我們知道:

  • 時間插值器用於對當前動畫的時間流逝百分比進行計算。
  • 插值器決定了動畫是按照線性執行還是按照非線性執行,比如加速或減速。
  • ValueAnimator預設插值器是加速加速插值器(AccelerateDecelerateInterpolator)。
  • setInterpolator()方法傳一個空(null)值,會返回一個線性插值器

繼續看ValueAnimator的原始碼,找到了下面這個方法——animateValue(),從這個方法的註釋我們知道了它的作用:
1. 此方法會在 每一個動畫幀 伴隨 時間流逝分數(elapsed fraction) 被呼叫。
2. 此方法將時間流逝分數轉變成一個插值分數,然後轉變成一個動畫值(通過計算器evaluator)。
3. 該方法主要在動畫更新過程中調動,但也在end()方法呼叫時呼叫來設定屬性的終值。
4. 該方法的引數是時間流逝分數(elapsed fraction)。

/**
 * This method is called with the elapsed fraction of the animation during every
 * animation frame. This function turns the elapsed fraction into an interpolated fraction
 * and then into an animated value (from the evaluator). The function is called mostly during
 * animation updates, but it is also called when the <code>end()</code>
 * function is called, to set the final value on the property.
 *
 * <p>Overrides of this method must call the superclass to perform the calculation
 * of the animated value.</p>
 *
 * @param fraction The elapsed fraction of the animation.
 */
@CallSuper
void animateValue(float fraction) {
    fraction = mInterpolator.getInterpolation(fraction);
    mCurrentFraction = fraction;
    int numValues = mValues.length;
    for (int i = 0; i < numValues; ++i) {
        mValues[i].calculateValue(fraction);
    }
    if (mUpdateListeners != null) {
        int numListeners = mUpdateListeners.size();
        for (int i = 0; i < numListeners; ++i) {
            mUpdateListeners.get(i).onAnimationUpdate(this);
        }
    }
}

上面animateValue()方法的原始碼中我們找到了這行程式碼
fraction = mInterpolator.getInterpolation(fraction);
表示插值器呼叫getInterpolation(fraction)對時間流逝分數(elapsed fraction)進行計算,獲得一個fraction,這個fraction就是插值分數(interpolated fraction)。
方法的最後,我們發現此方法遍歷了UpdateListener集合,並呼叫了每一個UpdateListener(ValueAnimator.AnimatorUpdateListener)的onAnimationUpdate方法,並把ValueAnimator自己作為引數傳了過去。

2.2 自定義插值器

自定以插值期之前,我們先看一下ValueAnimator預設的插值器原始碼是怎麼實現的:
AccelerateDecelerateInterpolator

/**
 * An interpolator where the rate of change starts and ends slowly but
 * accelerates through the middle.
 */
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }

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

BaseInterpolator

/**
 * An abstract class which is extended by default interpolators.
 */
abstract public class BaseInterpolator implements Interpolator {
    private int mChangingConfiguration;
    /**
     * @hide
     */
    public int getChangingConfiguration() {
        return mChangingConfiguration;
    }

    /**
     * @hide
     */
    void setChangingConfiguration(int changingConfiguration) {
        mChangingConfiguration = changingConfiguration;
    }
/**
 * An interpolator defines the rate of change of an animation. This allows
 * the basic animation effects (alpha, scale, translate, rotate) to be 
 * accelerated, decelerated, repeated, etc.
 */
public interface Interpolator extends TimeInterpolator {
    // A new interface, TimeInterpolator, was introduced for the new android.animation
    // package. This older Interpolator interface extends TimeInterpolator so that users of
    // the new Animator-based animations can use either the old Interpolator implementations or
    // new classes that implement TimeInterpolator directly.
}

從上面原始碼中我們看到AccelerateDecelerateInterpolator繼承自BaseInterpolator,BaseInterpolator實現了Interpolator,而Interpolator繼承自TimeInterpolator。下面我們直接看TimeInterpolator介面的原始碼:

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

3.計算器

4. keyFrame–關鍵幀