Android技能樹 — 動畫小結

最近年末了,打算把本身的Android知識都整理一下。html

Android技能書系列:java

Android基礎知識android

Android技能樹 — 動畫小結git

Android技能樹 — View小結github

Android技能樹 — Activity小結算法

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

Android技能樹 — Android存儲路徑及IO操做小結數組

Android技能樹 — 多進程相關小結bash

Android技能樹 — Drawable小結數據結構

數據結構基礎知識

Android技能樹 — 數組,鏈表,散列表基礎小結

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

算法基礎知識

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

最近整理了下本身學過的動畫方面的知識。用百度腦圖作了動畫知識的思惟腦圖,哪裏若是以爲不對,你們能夠留言提出哦。

你沒看錯,掘金的文章的圖片,電腦上看這種思惟腦圖根本就看不清楚,因此我準備一塊塊來說。 (掘金手機版APP卻是能夠放大,看的挺清晰的。)

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

AnimationSummay腦圖


動畫能夠分爲兩類:Animation 和 Transition二類。

Animation

由於通常來講第二塊Animation用的比較多,因此咱們先來看Animation這塊:

好的,咱們能夠看到咱們的Animation能夠分紅:

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

咱們能夠按順序一個個來看:

幀動畫:

幀動畫我就很少說了,就是提早準備好一個連續的圖片,而後一張張切換,就相似gif圖播放同樣。注意點就是圖片數量過多而且圖片較大,容易出現OOM。

View動畫:

1. 四種基本動畫:

咱們能夠看到,其實View動畫很簡單,基本使用的是「平移」,「縮放」,「旋轉」,「透明度」四種基本動畫。

2. LayoutAnimation 及 界面切換動畫:

而後咱們看特殊場景下的View動畫:

LayoutAnimaion : 在ViewGroup中,View動畫能夠用來控制子元素的出場效果,好比咱們的應用中的列表,咱們在加載列表中的子項的時候,可讓item加載的時候不是忽然出現,能夠伴隨各類動畫。

好比:

這裏的界面切換動畫,與最剛開始的大分類的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動畫注意事項:

這裏咱們能夠看到,View動畫其實並非真得改變了View的狀態,好比說咱們寫了一個按鈕,點擊按鈕能夠Toast一段內容,經過Translate動畫從左邊平移到了右邊,這時候雖然按鈕看上去在右邊了,可是這時候你點擊按鈕,並不會出現Toast的內容,可是你點擊左邊的按鈕初始位置,卻有Toast內容。由於其實按鈕只是影像移動過去而已。真正的按鈕仍是在原始位置。

也許有人會問,那若是我就是但願按鈕移動到右邊後,點擊右邊的按鈕能夠有點擊事件,你能夠選擇後面提到的屬性動畫,或者若是你必定要用View動畫,那你能夠在右邊目標位置,提早準備一個如出一轍的而且隱藏的按鈕,而後當左邊的按鈕移動到右邊後,咱們能夠設置右邊的隱藏的按鈕出現,而後把左邊的最初的按鈕進行隱藏便可。

屬性動畫:

首先你們能夠看下扔物線大佬的相關這個知識點的文章:

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

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

1. ViewPropertyAnimator:

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

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

ViewPropertyAnimator多個動畫進行:

若是想多個動畫同時進行,只須要簡單的:

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

2. ObjectAnimator:

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

動畫操做使用方式:
  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();
複製代碼

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();
複製代碼

3. ValueAnimator:

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:

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. 插值器 與 估值器

插值器(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 過渡(Transition)動畫解析之基礎篇

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

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

Activity和Fragment Transition介紹

深刻理解Content Transition

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

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

項目需求討論 — 用Transition作一個漂亮的登陸界面

相關文章
相關標籤/搜索