一窺 Android 動畫

做者:不洗碗工做室 - catango
文章出處: Android動畫
版權歸做者全部,轉載請註明出處前端

前言

動畫效果一直是人機交互的一個很是重要的部分,動畫效果的引入,會讓交互變得更加友好,讓用戶得到更加愉悅的體驗。做爲一個前端開發者,動畫也是一個必會的技能。java

View Animation

View Animation包含了Tween Animation、Frame Animation(Drawable Animation)。這些都是在安卓3.0以前的兩種動畫。android

幀動畫

幀動畫有時也叫Drawable動畫,它容許你實現像播放幻燈片同樣的效果,這種動畫的實質實際上是Drawable,因此這種動畫的XML定義方式文件 通常放在res/drawable/目錄下。幀動畫的動畫本質呢就是咱們的視覺殘留。canvas

通常咱們會先在Drawable下面將動畫資源引用好,而後在代碼中調用start()/stop()來開始或者中止播放動畫。固然咱們也能夠在Java代碼中建立逐幀動畫,建立AnimationDrawable對象,而後調用 addFrame(Drawable frame,int duration)向動畫中添加幀,接着調用start()和stop()而已~推薦是使用XML來定義動畫。bash

具體的標籤有:app

  • <animation-list>:必須是根節點,包含多個< item>元素。屬性有android:oneshot true表明只執行一次,false循環執行。
  • < item>:animation-list的子項,包含的屬性有:
    • android:drawable 一個frame的Drawable資源。
    • android:duration 一個frame顯示多長時間。

舉個例子,咱們在drawable中ide

< ?xml version="1.0" encoding="utf-8"?>

< animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    < item android:drawable="@color/black" android:duration="300"/>
    < item android:drawable="@color/white" android:duration="300"/>
< /animation-list>複製代碼

而後在kotlin中函數

img_test.apply {
            setBackgroundResource(R.drawable.test_frame)
            setOnClickListener {
                if ((background as AnimationDrawable).isRunning)
                    (background as AnimationDrawable).stop()
                else (background as AnimationDrawable).start()
            }
        }複製代碼

這樣當咱們點擊圖片的時候就會自動播放在drawable中設置的資源了。
注意,Animation的start方法不能在Activity的onCreate方法中調用,由於AnimationDrawable還未徹底附着到Window上。佈局

補間動畫

Tween Animation(補間動畫)只能應用於View對象,並且只支持一部分屬性,如支持縮放旋轉而不支持背景顏色的改變。並且對於Tween Animation,並不改變屬性的值,它只是改變了View對象繪製的位置,而沒有改變View對象自己,好比,你有一個Button,座標(100,100),Width:100,Height:100,而你有一個動畫使其移動(200,200),你會發現動畫過程當中觸發按鈕點擊的區域還是(100,100)-(200,200)。 動畫

補間動畫經過XML或Android代碼定義,建議仍是使用XML文件定義,由於它更具可讀性、可重用性。這裏說一下,補間動畫的全部父類都是它:

public abstract class Animation implements Cloneable複製代碼

這個注意和屬性動畫的父類區分。

java類名 xml關鍵字 描述信息
AlphaAnimation 放置在res/anim/目錄下 漸變透明度動畫效果
RotateAnimation 放置在res/anim/目錄下 畫面轉移旋轉動畫效果
ScaleAnimation 放置在res/anim/目錄下 漸變尺寸伸縮動畫效果
TranslateAnimation 放置在res/anim/目錄下 畫面轉換位置移動動畫效果
AnimationSet 放置在res/anim/目錄下 一個持有其它動畫元素alpha、scale、translate、rotate或者其它set元素的容器

Animation屬性

xml屬性 java方法 解釋
android:detachWallpaper setDetachWallpaper(boolean) 是否在壁紙上運行
android:duration setDuration(long) 動畫持續時間,毫秒爲單位
android:fillAfter setFillAfter(boolean) 控件動畫結束時是否保持動畫最後的狀態
android:fillBefore setFillBefore(boolean) 控件動畫結束時是否還原到開始動畫前的狀態
android:fillEnabled setFillEnabled(boolean) 與android:fillBefore效果相同
android:interpolator setInterpolator(Interpolator) 設定插值器(指定的動畫效果,譬如回彈等)
android:repeatCount setRepeatCount(int) 重複次數
android:repeatMode setRepeatMode(int) 重複類型有兩個值,reverse表示倒序回放,restart表示從頭播放
android:startOffset setStartOffset(long) 調用start函數以後等待開始運行的時間,單位爲毫秒
android:zAdjustment setZAdjustment(int) 表示被設置動畫的內容運行時在Z軸上的位置(top/bottom/normal),默認爲normal

Alpha屬性

xml屬性 java方法 解釋
android:fromAlpha AlphaAnimation(float fromAlpha, …) 動畫開始的透明度(0.0到1.0,0.0是全透明,1.0是不透明)
android:toAlpha AlphaAnimation(…, float toAlpha) 動畫結束的透明度,同上

Rotate屬性

xml屬性 java方法 解釋
android:fromDegrees RotateAnimation(float fromDegrees, …) 旋轉開始角度,正表明順時針度數,負表明逆時針度數
android:toDegrees RotateAnimation(…, float toDegrees, …) 旋轉結束角度,正表明順時針度數,負表明逆時針度數
android:pivotX RotateAnimation(…, float pivotX, …) 縮放起點X座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%作爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%作爲初始點)
android:pivotY RotateAnimation(…, float pivotY) 縮放起點Y座標,同上規律

Scale屬性

xml屬性 java方法 解釋
android:fromXScale ScaleAnimation(float fromX, …) 初始X軸縮放比例,1.0表示無變化
android:toXScale ScaleAnimation(…, float toX, …) 結束X軸縮放比例
android:fromYScale ScaleAnimation(…, float fromY, …) 初始Y軸縮放比例
android:toYScale ScaleAnimation(…, float toY, …) 結束Y軸縮放比例
android:pivotX ScaleAnimation(…, float pivotX, …) 縮放起點X軸座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%作爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%作爲初始點)
android:pivotY ScaleAnimation(…, float pivotY) 縮放起點Y軸座標,同上規律

Translate屬性詳解

xml屬性 java方法 解釋
android:fromXDelta TranslateAnimation(float fromXDelta, …) 起始點X軸座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%作爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%作爲初始點)
android:fromYDelta TranslateAnimation(…, float fromYDelta, …) 起始點Y軸從標,同上規律
android:toXDelta TranslateAnimation(…, float toXDelta, …) 結束點X軸座標,同上規律
android:toYDelta TranslateAnimation(…, float toYDelta) 結束點Y軸座標,同上規律

插值器

插值器是用來控制動畫的變化速度,能夠理解成動畫渲染器,固然咱們也能夠本身實現Interpolator 接口,自行來控制動畫的變化速度,而Android中已經爲咱們提供了五個可供選擇的實現類:

  • LinearInterpolator:動畫以均勻的速度改變
  • AccelerateInterpolator:在動畫開始的地方改變速度較慢,而後開始加速
  • AccelerateDecelerateInterpolator:在動畫開始、結束的地方改變速度較慢,中間時加速
  • CycleInterpolator:動畫循環播放特定次數,變化速度按正弦曲線改變: Math.sin(2 mCycles Math.PI * input)
  • DecelerateInterpolator:在動畫開始的地方改變速度較快,而後開始減速
  • AnticipateInterpolator:反向,先向相反方向改變一段再加速播放
  • AnticipateOvershootInterpolator:開始的時候向後而後向前甩必定值後返回最後的值
  • BounceInterpolator: 跳躍,快到目的值時值會跳躍,如目的值100,後面的值可能依次爲85,77,70,80,90,100
  • OvershottInterpolator:回彈,最後超出目的值而後緩慢改變到目的值

使用簡介:

上面這些都是補間動畫的一些xml和java方法的簡介,這些方法屬性記不住沒關係,我們能夠隨時查看的,最重要的仍是怎麼去用。其實用法也是特別簡單的,十分的套路,咱們只須要記住套路就能夠。咱們就舉個簡單的旋轉動畫的例子吧。

首先是XML

< ?xml version="1.0" encoding="utf-8"?>
< rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:duration="1000"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="infinite"
    />複製代碼

其中咱們用了@android:animaccelerate_decelerate_interpolator這個插值器,就是上面所說的DecelerateInterpolator在動畫開始的地方改變速度較快,而後開始減速。

寫完XML後,在java代碼中

Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_rotate);
    testImg.setAnimation(animation);
    animation.start();
    animation.cancel();複製代碼

咱們能夠看到,先建立了一個Animation對象,而後在用AnimationUtils的loadAnimation方法將XML裏定義的動畫加載到animation對象中,而後經過View的setAnimation方法將animation傳入,這樣就將這個動畫綁定到view上面了。最後經過animation的start和cancel方法來開始或者取消動畫。 其中咱們能夠爲animation設置動畫的監聽,這個特別簡單就再也不這贅述了...

Property Animation

Android 3.0之後引入了屬性動畫,屬性動畫能夠垂手可得的實現許多View動畫作不到的事。其實說白了,記住一點就行,屬性動畫實現原理就是修改控件的屬性值實現的動畫。固然,功能強大的代價就是使用起來要比較複雜。

屬性動畫全部的父類是它:

public abstract class Animator implements Cloneable複製代碼

這個注意要和補間動畫來區分。

接下來介紹一下相關的API:

  • Animator 建立屬性動畫的基類,通常不直接用,而是用他的兩個子類
  • ValueAnimator Animator的直接派生類。其內部採用一種時間循環的機制來計算值與值之間的動畫過分,咱們只需將初始值以及結束值提供給該類,並告訴其動畫所需時間長度,該類就會自動幫咱們從初始值平滑過分到結束。該類還能管理動畫的播放次數、模式和監聽器等。
  • AnimatorSet Animator的直接派生類,能夠組合多個Animator,並制定Animator的播放次序。
  • ObjectAnimator ValueAnimator的子類,容許咱們對指定對象的屬性執行動畫,用起來更簡單,實際中用得較多。
  • Evaluator 計算器,告訴動畫系統如何從初始值過分到結束值。提供了一下的幾種Evaluator:
    • IntEvaluator:用於計算int屬性
    • FloatEvaluator:用於計算float屬性
    • ArgbEvaluator:用於計算16進製表示顏色值的計算器
    • TypeEvaluator:上述計算類的公共接口,能夠本身實現接口完成自定義。

ValueAnimator

使用流程:

  1. 調用ValueAnimator的ofInt(),ofFloat()或ofObject()靜態方法建立ValueAnimator實例
  2. 調用實例的setXxx方法設置動畫持續時間,插值方式,重複次數等
  3. 調用實例的addUpdateListener添加AnimatorUpdateListener監聽器,在該監聽器中 能夠得到ValueAnimator計算出來的值,你能夠值應用到指定對象上~
  4. 調用實例的start()方法開啓動畫! 另外咱們能夠看到ofInt和ofFloat都有個這樣的參數:float/int... values表明能夠多個值!

舉個例子:

//按軌跡方程來運動
    private void lineAnimator() {
        width = ly_root.getWidth();
        height = ly_root.getHeight();
        ValueAnimator xValue = ValueAnimator.ofInt(height,0,height / 4,height / 2,height / 4 * 3 ,height);
        xValue.setDuration(3000L);
        xValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 軌跡方程 x = width / 2
                int y = (Integer) animation.getAnimatedValue();
                int x = width / 2;
                moveView(img_babi, x, y);
            }
        });
        xValue.setInterpolator(new LinearInterpolator());
        xValue.start();
    }


    private void moveView(View view, int rawX, int rawY) {
        int left = rawX - img_babi.getWidth() / 2;
        int top = rawY - img_babi.getHeight();
        int width = left + view.getWidth();
        int height = top + view.getHeight();
        view.layout(left, top, width, height);
    }複製代碼

其中moveView方法是將View從新佈局,xValue的值從參數列表就能夠看出,而後設置每次更新的監聽,在監聽中每次調用moveView方法來改變View的佈局。若是是組合動畫的話,咱們能夠這樣:

//縮放效果
    private void scaleAnimator(){

        final float scale = 0.5f;
        AnimatorSet scaleSet = new AnimatorSet();
        ValueAnimator valueAnimatorSmall = ValueAnimator.ofFloat(1.0f, scale);
        valueAnimatorSmall.setDuration(500);

        ValueAnimator valueAnimatorLarge = ValueAnimator.ofFloat(scale, 1.0f);
        valueAnimatorLarge.setDuration(500);

        valueAnimatorSmall.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scale = (Float) animation.getAnimatedValue();
                img_babi.setScaleX(scale);
                img_babi.setScaleY(scale);
            }
        });
        valueAnimatorLarge.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scale = (Float) animation.getAnimatedValue();
                img_babi.setScaleX(scale);
                img_babi.setScaleY(scale);
            }
        });

        scaleSet.play(valueAnimatorLarge).after(valueAnimatorSmall);
        scaleSet.start();
     }複製代碼

這個組合動畫咱們能夠用play after來設定動畫實例,而後動畫就先執行play的動畫再執行after的實例了。固然,相似的方法還有一個with,就是兩個動畫會一塊兒播放。

  • after(Animator anim) 將現有動畫插入到傳入的動畫以後執行
  • after(long delay) 將現有動畫延遲指定毫秒後執行
  • before(Animator anim) 將現有動畫插入到傳入的動畫以前執行
  • with(Animator anim) 將現有動畫和傳入的動畫同時執行

ObjectAnimator

相比於ValueAnimator,ObjectAnimator可能纔是咱們最常接觸到的類,由於ValueAnimator只不過是對值進行了一個平滑的動畫過渡,但咱們實際使用到這種功能的場景好像並很少。而ObjectAnimator則就不一樣了,它是能夠直接對任意對象的任意屬性進行動畫操做的,好比說View的alpha屬性。還有ObjectAnimator在設計的時候就沒有針對於View來進行設計,而是針對於任意對象的。

既然ObjectAnimator是繼承自ValueAnimator的,那麼它的用法應該是和ValueAnimator類似的。

ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f);複製代碼

其實這段代碼的意思就是ObjectAnimator會幫咱們不斷地改變textview對象中alpha屬性的值,從1f變化到0f。而後textview對象須要根據alpha屬性值的改變來不斷刷新界面的顯示,從而讓用戶能夠看出淡入淡出的動畫效果。

那麼textview對象中是否是有alpha屬性這個值呢?沒有,不只textview沒有這個屬性,連它全部的父類也是沒有這個屬性的!這就奇怪了,textview當中並無alpha這個屬性,ObjectAnimator是如何進行操做的呢?其實ObjectAnimator內部的工做機制並非直接對咱們傳入的屬性名進行操做的,而是會去尋找這個屬性名對應的get和set方法,所以alpha屬性所對應的get和set方法應該就是:

public void setAlpha(float value);  
public float getAlpha();複製代碼

ObjectAnimator的使用相比ValueAnimator簡單多了,咱們只須要將它實例化後,其餘的用法和ValueAnimator是同樣的。

動畫的監聽

接下來要說下動畫事件的監聽,上面咱們ValueAnimator的監聽器是 AnimatorUpdateListener,當值狀態發生改變時候會回調onAnimationUpdate方法!
除了這種事件外還有:動畫進行狀態的監聽, AnimatorListener,咱們能夠調用addListener方法 添加監聽器,而後重寫下面四個回調方法:

  • onAnimationStart():動畫開始
  • onAnimationRepeat():動畫重複執行
  • onAnimationEnd():動畫結束
  • onAnimationCancel():動畫取消

加入AnimatorListener的話,四個方法你都要重寫,這樣寫起來非常麻煩,不過Android已經給咱們提供好一個適配器類:AnimatorListenerAdapter,該類中已經把每一個接口 方法都實現好了,因此咱們這裏只寫一個回調方法也是能夠的。

Evaluator

咱們在調用屬性動畫的時候,用到了ofInt,ofFloat,ofObject這些靜態方法來建立ValueAnimator的實例,在例子中,咱們用到了ofInt,ofFloat,可是細心的同窗可能發現了,ValueAnimator還有個ofObject方法來構造ValueAnimator實例,那麼這個是幹什麼用的呢?

public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setObjectValues(values);
        anim.setEvaluator(evaluator);
        return anim;
    }複製代碼

咱們先戳進去看看這個源碼的參數。第一個參數是名爲TypeEvaluator的一個東西,這就是咱們要說的計算器,他是來告訴動畫系統如何從初始值過渡到結束值的。前面提到過,TypeEvaluator是全部Evaluator的基類,這裏再重複一遍,系統提供瞭如下的幾種Evaluator:

  • IntEvaluator:用於計算int屬性
  • FloatEvaluator:用於計算float屬性
  • ArgbEvaluator:用於計算16進製表示顏色值的計算器
  • TypeEvaluator:上述計算類的公共接口,能夠本身實現接口完成自定義。

固然,這些Evaluator都是TypeEvaluator實現。咱們先來看看TypeEvaluator這個接口長什麼樣吧:

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

}複製代碼

就這個一個evaluate方法,簡單吧?這裏面的三個參數的含義依次是:

  • fraction:動畫的完成度,咱們根據他來計算動畫的值應該是多少
  • startValue:動畫的起始值
  • endValue:動畫的結束值

那麼咱們來看看系統是如何實現TypeEvaluator這個接口的,我們就從IntEvaluator提及:

public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}複製代碼

實現了TypeEvaluator接口,重寫了evaluate方法,其中返回的是動畫的值。動畫的值是多少呢?咱們從IntEvaluator的return語句中能夠看出,動畫的值 = 初始值 + 完成度 * (結束值 - 初始值) 這樣當完成度爲100%的時候,動畫的值就是結束值了,一樣的還有FloatEvaluator等。細心的同窗也發現了,這個TypeEvaluator裏面傳入的是一個泛型,這個類型也就是咱們接下來自定義的Object.

如今咱們舉個自定義Evaluator的例子。

package com.example.yang.testkotlin.widget;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

/**
 * @author YangCihang
 * @since 17/10/18.
 * email yangcihang@hrsoft.net
 */

public class CircleAnimView extends View {
    public static final int RADIUS = 80;
    private Point currentPoint;
    private Paint mPaint;
    private int mColor;//必須寫這個屬性的get和set,不然動畫沒法識別color屬性

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

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

    public CircleAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }

    private void drawCircle(Canvas canvas) {
        float x = currentPoint.x;
        float y = currentPoint.y;
        //用canvas draw,所以此控件大小應該爲全屏大小才能夠從左上到右下
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }

    private void startAnimation() {
        Point startPoint = new Point(RADIUS, RADIUS);
        Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });

        ObjectAnimator objectAnimator = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
                Color.BLUE, Color.RED);
        //動畫集合將兩個動畫加到一塊兒,with同時播放
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(anim).with(objectAnimator);
        animatorSet.setStartDelay(1000L);
        animatorSet.setDuration(3000L);
        animatorSet.start();
    }

    /**
     * 座標變化
     */
    class PointEvaluator implements TypeEvaluator<Point> {

        @Override
        public Point evaluate(float fraction, Point startValue, Point endValue) {
            //初始值 + 完成度 * (結束值 - 初始值)
            int x = (int) (startValue.x + fraction * (endValue.x - startValue.x));
            int y = (int) (startValue.y + fraction * (endValue.y - startValue.y));
            return new Point(x, y);
        }
    }

    /**
     * 顏色變化
     */
    public class ColorEvaluator implements TypeEvaluator<Integer> {
        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            int alpha = (int) (Color.alpha(startValue) + fraction *
                    (Color.alpha(endValue) - Color.alpha(startValue)));
            int red = (int) (Color.red(startValue) + fraction *
                    (Color.red(endValue) - Color.red(startValue)));
            int green = (int) (Color.green(startValue) + fraction *
                    (Color.green(endValue) - Color.green(startValue)));
            int blue = (int) (Color.blue(startValue) + fraction *
                    (Color.blue(endValue) - Color.blue(startValue)));
            return Color.argb(alpha, red, green, blue);
        }
    }

    //color的get和set方法~
    public int getColor() {
        return mColor;
    }

    public void setColor(int color) {
        mColor = color;
        mPaint.setColor(color);
        invalidate();
    }
}複製代碼

在這裏咱們定義了兩個Evaluator類分別來表示座標變化和顏色變化。注意,咱們要改變color屬性的時候,必定要寫setColor和getColor方法,緣由上面已經說過了。

Interpolator

Interpolator中文譯名叫作插值器或者補間器。在補間動畫的時候咱們介紹了幾個經常使用的插值器,咱們能夠回頭去看看。補間動畫和屬性動畫均可以用插值器的。並且補間動畫還新增長了一個TimeInterpolator接口,該接口是用於兼容以前的Interpolator的(也就是Interpolator又繼承了TimeInterpolator接口),這使得全部過去的Interpolator實現類均可以直接拿過來 放到屬性動畫當中使用!咱們能夠調用動畫對象的setInterpolator()方法設置不一樣的Interpolator。好比:

animatorSet.setInterpolator(new AccelerateInterpolator(2f))複製代碼

括號裏面的值用於控制加速度的。

自定義Interpolator

咱們自定義Interpolator其實就只要實現TimeInterpolator就能夠了,重寫也就只須要重寫getInterpolation方法好比:

private class DecelerateAccelerateInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        if (input < 0.5) {
            return (float) (Math.sin(input * Math.PI) / 2);
        } else {
            return 1 - (float) (Math.sin(input * Math.PI) / 2);
        }
    }
}複製代碼

不過咱們若是須要作一些複雜的速率變化,就得須要數學功底了。

相關文章
相關標籤/搜索