1. 程式人生 > >Android 插值器 Interpolator 介紹

Android 插值器 Interpolator 介紹

插值器Interpolator 簡介

interpolator可以翻譯成插值器。
Android中interpolator最底層的介面如下:

package android.animation;

/**
 * 時間插值器定義了一個動畫的變化率。
 * 這讓動畫讓非線性的移動軌跡,例如加速和減速。
 * <hr/>
 * 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 { /** * 將動畫已經消耗的時間的分數對映到一個表示插值的分數。 * 然後將插值與動畫的變化值相乘來推匯出當前已經過去的動畫時間的動畫變化量。 * <hr/> * 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 一個01.0表示動畫當前點的值,0表示開頭。1表示結尾<br/> 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 插值。它的值可以大於1來超出目標值,也小於0來空破底線。<br/>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); }

TimeInterpolator是在Android API11時加入的之前類就叫Interpolator。
現在Interpolatro繼承了它。

package android.view.animation;

import android.animation.TimeInterpolator;

/**
 * 一個定義動畫變化率的插值器。
 * 它允許對基本的(如透明,縮放,平移,旋轉)進行加速,減速,重複等動畫效果
 * <hr/>
 * 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.
}

簡單插值器分析

注意下面的圖,對應你腦海中的插值的大小應該是斜率。

AccelerateInterpolator 加速插值器

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;

/**
 * 
 * 一個開始很慢然後不斷加速的插值器。
 * <hr/>
 * An interpolator where the rate of change starts out slowly and
 * and then accelerates.
 *
 */
public class AccelerateInterpolator implements Interpolator {
    private final float mFactor;
    private final double mDoubleFactor;

    public AccelerateInterpolator() {
        mFactor = 1.0f;
        mDoubleFactor = 2.0;
    }

    /**
     * Constructor
     * 
     * @param factor 
     *     動畫的快慢度。將factor設定為1.0f會產生一條y=x^2的拋物線。
增加factor到1.0f之後為加大這種漸入效果(也就是說它開頭更加慢,結尾更加快)
     *   <br/>Degree to which the animation should be eased. Seting
     *        factor to 1.0f produces a y=x^2 parabola(拋物線). Increasing factor above
     *        1.0f  exaggerates the ease-in effect (i.e., it starts even
     *        slower and ends evens faster)
     */
    public AccelerateInterpolator(float factor) {
        mFactor = factor;
        mDoubleFactor = 2 * mFactor;
    }

    public AccelerateInterpolator(Context context, AttributeSet attrs) {
        TypedArray a =
                context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);

        mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
        mDoubleFactor = 2 * mFactor;

        a.recycle();
    }

    @Override
    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }
}

加速的快慢度由引數fractor決定。
當fractor值為1.0f時,動畫加速軌跡相當於一條y=x^2的拋物線。如下圖:
這裡寫圖片描述

當fractor不為1時,軌跡曲線是y=x^(2*fractor)(0< x <=1)的曲線。
示例:當fractor為4時,插值器的加速軌跡曲線如下圖:
這裡寫圖片描述

Android提供的一個不同factor的加速插值器:
(1)accelerate_cubic, factor為1.5

DecelerateInterpolator 減速插值器

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;

/**
 * 一個開始比較快然後減速的插值器
 * <hr/>
 * An interpolator where the rate of change starts out quickly and
 * and then decelerates.
 *
 */
public class DecelerateInterpolator implements Interpolator {
    public DecelerateInterpolator() {
    }

    /**
     * Constructor
     * 
     * @param factor
     *        動畫的快慢度。將factor值設定為1.0f時將產生一條從上向下的y=x^2拋物線。
     *        增加factor到1.0f以上將使漸入的效果增強(也就是說,開頭更快,結尾更慢)
     *        <br/>
     *        Degree to which the animation should be eased. Setting factor to 1.0f produces
     *        an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
     *        ease-out effect (i.e., it starts even faster and ends evens slower)
     */
    public DecelerateInterpolator(float factor) {
        mFactor = factor;
    }

    public DecelerateInterpolator(Context context, AttributeSet attrs) {
        TypedArray a =
                context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator);

        mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f);

        a.recycle();
    }

    @Override
    public float getInterpolation(float input) {
        float result;
        if (mFactor == 1.0f) {
            result = (1.0f - ((1.0f - input) * (1.0f - input)));
        } else {
            result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
        }
        return result;
    }

    private float mFactor = 1.0f;
}

根據getInterpolationa(float input);方法可以知道。
當fractor為1.0f。它減速的軌跡曲線為1-(1-x)^2。如下圖:
這裡寫圖片描述

當fractor增大到4時,曲線軌跡如下圖:
這裡寫圖片描述

AccelerateDecelerateInterpolator 加速減速插值器

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.util.AttributeSet;

/**
 * 一個變化率開始慢從中間後開始變快。
 * <hr/>
 * An interpolator where the rate of change starts and ends slowly but
 * accelerates through the middle.
 * 
 */
public class AccelerateDecelerateInterpolator implements Interpolator {
    public AccelerateDecelerateInterpolator() {
    }

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

    @Override
    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
}

根據getInterpolation()方法可以得出其變化曲線如下:
這裡寫圖片描述

LinearInterpolator 線性插值器

這可是最簡單的插值器:

/**
 * An interpolator where the rate of change is constant
 *
 */
public class LinearInterpolator implements Interpolator {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;
    }
}

BounceInterpolator 彈跳插值器

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.util.AttributeSet;

/**
 * 這個插值器的插值在後面呈彈跳狀態。
 * An interpolator where the change bounces at the end.
 */
public class BounceInterpolator implements Interpolator {
    public BounceInterpolator() {
    }

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

    private static float bounce(float t) {
        return t * t * 8.0f;
    }

    @Override
    public float getInterpolation(float t) {
        // _b(t) = t * t * 8
        // bs(t) = _b(t) for t < 0.3535
        // bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408
        // bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644
        // bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0
        // b(t) = bs(t * 1.1226)
        t *= 1.1226f;
        if (t < 0.3535f) return bounce(t);
        else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
        else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
        else return bounce(t - 1.0435f) + 0.95f;
    }
}

根據getInterpolation()得到以下插值曲線圖:

這裡寫圖片描述
(這個插值器的作圖函式我得記錄下來啊)

plot Piecewise[{ {(1.1226x)^2*8,0<x<0.3535}, {((1.1226x)-0.54719)^2*8+0.7,0.3535<=x<0.7408}, {((1.1226x)-0.8526)^2*8+0.9,0.7408<=x<0.9644}, {((1.1226x)-1.0435)^2*8+0.95,0.9644<=x<=1}}]

AnticipateInterpolator 迴盪鞦韆插值器

這個插值器的值變化過程,可以想像成盪鞦韆時的一個段過程。(此時鞦韆已經在比較上面的位置了,一放手就可以蕩下來)。你開始用力推向更上面,然後鞦韆終將蕩回下面。

tension值就好比推力的大小。

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;

/**
 * 一個開始向後蕩,然後向前蕩的插值器。
 * <hr/>
 * An interpolator where the change starts backward then flings forward.
 */
public class AnticipateInterpolator implements Interpolator {
    private final float mTension;

    public AnticipateInterpolator() {
        mTension = 2.0f;
    }

    /**
     * @param tension 
     *  繃緊程度,當繃緊程式為0.0f時,也就沒有了反向作用力。插值器將退化成一個y=x^3的加速插值器。
     * <br/>
     * Amount of anticipation. When tension equals 0.0f, there is
     *                no anticipation and the interpolator becomes a simple
     *                acceleration interpolator.
     */
    public AnticipateInterpolator(float tension) {
        mTension = tension;
    }

    public AnticipateInterpolator(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.AnticipateInterpolator);

        mTension =
                a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f);

        a.recycle();
    }

    @Override
    public float getInterpolation(float t) {
        // a(t) = t * t * ((tension + 1) * t - tension)
        return t * t * (((mTension + 1) * t) - mTension);
    }
}

根據getInterpolation()方法。
當tension為預設值2.0f時,曲線圖如下:
這裡寫圖片描述

當tension值為4.0f時,曲線圖如下:
這裡寫圖片描述

AnticipateOvershootInterpolator

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;

/**
 * 一個插值器它開始向上推,然後向下蕩,蕩過最低線。然後再回到最低線。
 * <hr/>
 * An interpolator where the change starts backward then flings forward and overshoots
 * the target value and finally goes back to the final value.
 */
public class AnticipateOvershootInterpolator implements Interpolator {
    private final float mTension;

    public AnticipateOvershootInterpolator() {
        mTension = 2.0f * 1.5f;
    }

    /**
     * @param tension 
     *  anticipation/overshoot的比值。當和tension值為0.0f時,
     *  也就沒有anticipation/overshoot的比值了,插值器退化為一個加速/減速插值器。
     *  <br/>
     * Amount of anticipation/overshoot. When tension equals 0.0f,
     *                there is no anticipation/overshoot and the interpolator becomes
     *                a simple acceleration/deceleration interpolator.
     */
    public AnticipateOvershootInterpolator(float tension) {
        mTension = tension * 1.5f;
    }

    /**
     * @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
     *                there is no anticipation/overshoot and the interpolator becomes
     *                a simple acceleration/deceleration interpolator.
     * @param extraTension 
     * 乘以tension的值。例如,在上面建構函式中extraTension的值為1.5f
     * <br/>
     * Amount by which to multiply the tension. For instance,
     *                     to get the same overshoot as an OvershootInterpolator with
     *                     a tension of 2.0f, you would use an extraTension of 1.5f.
     */
    public AnticipateOvershootInterpolator(float tension, float extraTension) {
        mTension = tension * extraTension;
    }

    public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator);

        mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
                a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);

        a.recycle();
    }

    private static float a(float t, float s) {
        return t * t * (((s + 1) * t) - s);
    }

    private static float o(float t, float s) {
        return t * t * (((s + 1) * t) + s);
    }

    @Override
    public float getInterpolation(float t) {
        // a(t, s) = t * t * ((s + 1) * t - s)
                // o(t, s) = t * t * ((s + 1) * t + s)
        // f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5
        // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0
        if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
        else return 0.5f * (o((t * 2.0f) - 2.0f, mTension) + 2.0f);
    }
}

根據getInterpolation()方法,
可以得到當tension為預設值時,曲線圖為:

plot Piecewise[{{0.5((2x)(2x)((2+1)2x-2)), 0 < x < 0.5}, {0.5(((2x-2)(2x-2)((2+1)*(2x-2)+2))+2),0.5 <= x <= 1}}]

(不知道我的plot函式寫對了沒?)
這裡寫圖片描述

CycleInterpolator 正弦週期變化插值器

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;

/**
 * 
 * 以指定的週期重複動畫。變化率曲線為正弦。
 * <hr/>
 * Repeats the animation for a specified number of cycles(週期). The
 * rate of change follows a sinusoidal(正弦) pattern.
 *
 */
public class CycleInterpolator implements Interpolator {
    /**
     * 
     * @param cycles 要重複的週期數
     */
    public CycleInterpolator(float cycles) {
        mCycles = cycles;
    }

    public CycleInterpolator(Context context, AttributeSet attrs) {
        TypedArray a =
                context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator);

        mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f);

        a.recycle();
    }

    @Override
    public float getInterpolation(float input) {
        return (float)(Math.sin(2 * mCycles * Math.PI * input));
    }

    private float mCycles;
}

當cycle時為1時,即變化一週時,曲線圖如下:
這裡寫圖片描述

OvershootInterpolator

原始碼如下:

package android.view.animation;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;

/**
 * An interpolator where the change flings forward and overshoots the last value
 * then comes back.
 */
public class OvershootInterpolator implements Interpolator {
    private final float mTension;

    public OvershootInterpolator() {
        mTension = 2.0f;
    }

    /**
     * @param tension Amount of overshoot. When tension equals 0.0f, there is
     *                no overshoot and the interpolator becomes a simple
     *                deceleration interpolator.
     */
    public OvershootInterpolator(float tension) {
        mTension = tension;
    }

    public OvershootInterpolator(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.OvershootInterpolator);

        mTension =
                a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f);

        a.recycle();
    }

    @Override
    public float getInterpolation(float t) {
        // _o(t) = t * t * ((tension + 1) * t + tension)
        // o(t) = _o(t - 1) + 1
        t -= 1.0f;
        return (t * t * (((mTension + 1) * t) + mTension)) + 1.0f;
        //plot {(x-1)(x-1)((tension+1)(x-1)+tension)+1,(0<x<=1)}
    }
}

當tension為預設值2時,曲線圖如下:
這裡寫圖片描述

當tension的值為4時,曲線圖如下:
這裡寫圖片描述