Android技能樹 — 動畫小結

青蛙要fly發表於2018-01-26

最近年底了,打算把自己的Android知識都整理一下。

Android技能書系列:

Android基礎知識

Android技能樹 — 動畫小結

Android技能樹 — View小結

Android技能樹 — Activity小結

Android技能樹 — View事件體系小結

Android技能樹 — Android儲存路徑及IO操作小結

Android技能樹 — 多程式相關小結

Android技能樹 — Drawable小結

資料結構基礎知識

Android技能樹 — 陣列,連結串列,雜湊表基礎小結

Android技能樹 — 樹基礎知識小結(一)

演算法基礎知識

Android技能樹 — 排序演算法基礎小結

最近整理了下自己學過的動畫方面的知識。用百度腦圖做了動畫知識的思維腦圖,哪裡如果覺得不對,大家可以留言提出哦。

Android技能樹 — 動畫小結

你沒看錯,掘金的文章的圖片,電腦上看這種思維腦圖根本就看不清楚,所以我準備一塊塊來講。 (掘金手機版APP倒是可以放大,看的挺清晰的。)

總結的圖已經傳到了Github上面,可以下載:

AnimationSummay腦圖


動畫可以分為兩類:Animation 和 Transition二類。

Android技能樹 — 動畫小結

Animation

因為一般來說第二塊Animation用的比較多,所以我們先來看Animation這塊:

Android技能樹 — 動畫小結

好的,我們可以看到我們的Animation可以分成:

  1. 幀動畫
  2. View動畫
  3. Property動畫(屬性動畫)

我們可以按順序一個個來看:

幀動畫:

Android技能樹 — 動畫小結
幀動畫我就不多說了,就是提前準備好一個連續的圖片,然後一張張切換,就類似gif圖播放一樣。注意點就是圖片數量過多並且圖片較大,容易出現OOM。

View動畫:

Android技能樹 — 動畫小結

1. 四種基本動畫:

我們可以看到,其實View動畫很簡單,基本使用的是“平移”,“縮放”,“旋轉”,“透明度”四種基本動畫。

2. LayoutAnimation 及 介面切換動畫:

然後我們看特殊場景下的View動畫:

Android技能樹 — 動畫小結
LayoutAnimaion : 在ViewGroup中,View動畫可以用來控制子元素的出場效果,比如我們的應用中的列表,我們在載入列表中的子項的時候,可以讓item載入的時候不是突然出現,可以伴隨各種動畫。

比如:

Android技能樹 — 動畫小結

這裡的介面切換動畫,與最剛開始的大分類的Transition不同,這裡的過渡的動畫用的是View動畫,比如Activity的切換效果:

//當啟動一個Activity時
Intent intent = new Intent(this,XXXXX.class);
startActivity(intent);
overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);

//當Activity退出時
@Override 
public void finish(){
    super.finish();
    overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
}
複製程式碼

其中我們可以看到主要是用到overridePendingTransition方法,這個方法必須放在startActivity()finish()後面。

3. View動畫注意事項:

Android技能樹 — 動畫小結
這裡我們可以看到,View動畫其實並不是真得改變了View的狀態,比如說我們寫了一個按鈕,點選按鈕可以Toast一段內容,通過Translate動畫從左邊平移到了右邊,這時候雖然按鈕看上去在右邊了,但是這時候你點選按鈕,並不會出現Toast的內容,但是你點選左邊的按鈕初始位置,卻有Toast內容。因為其實按鈕只是影像移動過去而已。真正的按鈕還是在原始位置。

也許有人會問,那如果我就是希望按鈕移動到右邊後,點選右邊的按鈕可以有點選事件,你可以選擇後面提到的屬性動畫,或者如果你一定要用View動畫,那你可以在右邊目標位置,提前準備一個一模一樣的並且隱藏的按鈕,然後當左邊的按鈕移動到右邊後,我們可以設定右邊的隱藏的按鈕出現,然後把左邊的最初的按鈕進行隱藏即可。

屬性動畫:

Android技能樹 — 動畫小結

首先大家可以看下扔物線大佬的相關這個知識點的文章:

HenCoder Android 自定義 View 1-6: 屬性動畫(上手篇)

【HenCoder Android 開發進階】自定義 View 1-7:屬性動畫(進階篇)

1. ViewPropertyAnimator:

Android技能樹 — 動畫小結

我直接引用了扔物線大佬文章裡面的相關動畫操作的圖片:

Android技能樹 — 動畫小結

用ViewPropertyAnimator 來做屬性動畫是最簡單的。特別方便。

ViewPropertyAnimator多個動畫進行:

如果想多個動畫同時進行,只需要簡單的:

view.animate()
        .scaleX(1)
        .scaleY(1)
        .alpha(1);
複製程式碼

2. ObjectAnimator:

Android技能樹 — 動畫小結

引用扔物線大佬裡面的內容:

動畫操作使用方式:
  1. 如果是自定義控制元件,需要新增 setter / getter 方法;
  2. 用 ObjectAnimator.ofXXX() 建立 ObjectAnimator 物件;
  3. 用 start() 方法執行動畫。
public class SportsView extends View {

    float progress = 0;

    ......

    // 建立 getter 方法
    public float getProgress() {
        return progress;
    }

    // 建立 setter 方法
    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        ......

        canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint);

        ......
    }
}

......

// 建立 ObjectAnimator 物件
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65);
// 執行動畫
animator.start();
複製程式碼

Android技能樹 — 動畫小結

ObjectAnimation多個動畫同時進行 - PropertyValuesHolder:

ObjectAnimation在多個動畫一起進行的時候不能像ViewPropertyAnimation那樣方便,不過你可以使用 PropertyValuesHolder 來同時在一個動畫中改變多個屬性:

PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)
animator.start();
複製程式碼

PropertyValuesHolder 的意思從名字可以看出來,它是一個屬性值的批量存放地。所以你如果有多個屬性需要修改,可以把它們放在不同的 PropertyValuesHolder 中,然後使用 ofPropertyValuesHolder() 統一放進 Animator。這樣你就不用為每個屬性單獨建立一個Animator 分別執行了。

PropertyValuesHolder - Keyframe:

PropertyValuesHolders.ofKeyframe()把同一個屬性拆分 除了合併多個屬性和調配多個動畫,你還可以在 PropertyValuesHolder 的基礎上更進一步,通過設定 Keyframe (關鍵幀),把同一個動畫屬性拆分成多個階段。
例如,你可以讓一個進度增加到 100% 後再「反彈」回來。

// 在 0% 處開始
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 時間經過 50% 的時候,動畫完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 時間見過 100% 的時候,動畫完成度倒退到 80%,即反彈 20%
Keyframe keyframe3 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);
animator.start();
複製程式碼

Android技能樹 — 動畫小結

3. ValueAnimator:

Android技能樹 — 動畫小結
ViewPropertyAnimator 和 ObjectAnimator的底部都是用ValueAnimator實現的,從字面意思就可以看出是數值的動畫,也就是數值的變化。
比如:

ValueAnimator valueAnimator = ValueAnimator.ofInt(1,5);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int value = (int) animation.getAnimatedValue();//當前的值
    }
});
複製程式碼

我們可以看到ValueAnimator是監聽到當前變化到哪個值了。然後你拿著這個值想怎麼處理,就是你的事了。所以ValueAnimator就更基礎。


所以你看,ViewPropertyAnimator、ObjectAnimator、ValueAnimator 這三種 Animator,它們其實是一種遞進的關係:從左到右依次變得更加難用,也更加靈活。但我要說明一下,它們的效能是一樣的,因為 ViewPropertyAnimator 和 ObjectAnimator 的內部實現其實都是 ValueAnimator,ObjectAnimator 更是本來就是 ValueAnimator 的子類,它們三個的效能並沒有差別。它們的差別只是使用的便捷性以及功能的靈活性。所以在實際使用時候的選擇,只要遵循一個原則就行:儘量用簡單的。能用 View.animator() 實現就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator。

4. AnimationSet:

Android技能樹 — 動畫小結

AnimationSet為什麼要把這個單獨拎出來呢。AnimationSet可以用在多個動畫播放,很多人就說了,上面我們在ViewPropertyAnimator 及ObjectAnimation中的PropertyValuesHolder已經可以用在多個動畫一起播放了嗎?沒錯,問題就出在這個<一起>這二個字上面,因為上面的二個都是隻能N個動畫同時播放,比如我現在的需求是先平移,然後平移結束後再放大和改變透明度。而AnimationSet及可以一起播放,又可以控制動畫的先後順序來。

ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);
animator1.setInterpolator(new LinearInterpolator());
ObjectAnimator animator2 = ObjectAnimator.ofInt(...);
animator2.setInterpolator(new DecelerateInterpolator());

AnimatorSet animatorSet = new AnimatorSet();
// 兩個動畫依次執行
animatorSet.playSequentially(animator1, animator2);
animatorSet.start();
複製程式碼

使用 playSequentially(),就可以讓兩個動畫依次播放,而不用為它們設定監聽器來手動為他們監管協作。 AnimatorSet 還可以這麼用:

// 兩個動畫同時執行
animatorSet.playTogether(animator1, animator2);
animatorSet.start();以及這麼用:
// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式來精確配置各個 Animator 之間的關係
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);
animatorSet.start();
複製程式碼

有了 AnimatorSet ,你就可以對多個 Animator 進行統一規劃和管理,讓它們按照要求的順序來工作。

5. 插值器 與 估值器

Android技能樹 — 動畫小結

插值器(Interpolator)和 估值器(Evaluator)大家肯定也見過很多次,那這二個到底是用來幹嘛的呢?

我們從頭來分析一個平移的動畫:

  1. 我們告訴一個View,5秒內,從左到右移動500px的距離。
  2. 時間經歷到了 N 秒的時候,我們要知道整個動畫到了哪個程度,比如動畫執行了50% 了。
  3. 當動畫執行到某個程式的時候(比如執行了50%),這時候我們的X軸的移動距離的值具體是多少px。
  4. 然後View通過獲取到的具體的移動距離的px值,去設定View的translationX的屬性,讓View去移動。

那我們的插值器和估值器是用在哪裡呢:
插值器是用在第二步裡面,時間經歷了N秒,我們返回一個值,這個值是說明當前動畫進行到哪個程度了。
估值器是用在第三步,我們已經知道了動畫執行到了哪個程式,然後我們返回具體的當前變化的數值。

比如我們來看LinearInterpolator.javaIntEvaluator.java的原來再理解下:

public class LinearInterpolator implements Interpolator{
    
    public LinearInterpolator(){
    }
    
    public LinearInterpolator(Context context,AttributeSet attrs){
    }
    
    public float getInterpolation(float input){
        //比如時間是5秒,這時候過了2.5秒,這時候時間流逝了0.5,所以input是0.5
        //因為我們這個LiearInterpolator是線性插值器,
        //所以時間流失了0.5,我們的動畫的動畫也執行了0.5(也就是完成了50%的程度)
        //所以這裡直接返回input即可。
        return input;
    }
    
}
複製程式碼
public class IntEvaluator implements TypeEvaluator<Integer>{
    
    public Integer evaluate(float fraction,Integer startValue,Integer endValue){
        
        //fraction就是我們上面插值器返回的,告訴我們動畫執行到什麼程度了。
        //startValue是我們起始值,endValue是我們最後的目標值。
        //比如我們是ofInt(0,500);這時候我們return的值就是(0+0.5 * (500-0))= 250 
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startValue));
    }
}
複製程式碼

Transition

Android技能樹 — 動畫小結
Android技能樹 — 動畫小結
Android技能樹 — 動畫小結

過於過渡,我也不費心思全部很詳細的寫出來,網上的基本介紹及使用有很多。

基本知識:

Android 過渡(Transition)動畫解析之基礎篇

酷炫的Activity切換動畫,打造更好的使用者體驗

稍微深度過渡動畫基本原理:

Activity和Fragment Transition介紹

深入理解Content Transition

深入理解共享元素變換(Shared Element Transition)-上

這裡我也用過渡寫過相關效果的文章:

專案需求討論 — 用Transition做一個漂亮的登入介面

相關文章