【Android】使用屬性動畫碰到的困惑及講解



屬性動畫的教程網上已經特別多了,本篇也不打算再去各種詳解知識點,主要就是記錄題主學習屬性動畫時的碰到的一些困惑,以及后來自己的理解。如果有人也碰到相似的問題,正好可以一起討論下。


概要

本篇主要涉及的知識點包括:

  1. ObjectAnimator
  2. ValueAnimator

老規矩,首先先來看下效果圖:

這種折疊/展開,隱藏/顯示的動畫在很多地方都會有用到,如果再加上使用5.0后引進的Z屬性,實現各種酷炫的立體動畫就更吸引人了。所以,還是先掌握好這基礎的屬性動畫吧。

分析

如果你還對屬性動畫不太明白,或者沒用過ObjectAnimator、ValueAnimator的話,建議先去看下郭神的這篇

從上圖很容易可以看出,這需要用到translationX/Y屬性,即平移的屬性。也許你會覺得,這不是很簡單嗎,不就設置下平移的起止值,動畫時長,搞定。

沒錯,是很簡單,就是這么實現的。但其實,對於新手來說,知道怎么做和把它做出來其實還是兩碼事。題主也還是個初學者,當初也是覺得這很簡單啊,然后自己做的時候卻出現了各種問題。下面就來講講題主做的過程中碰到的一些問題吧。

1、平移的距離如何確定?

先來看那個豎直收縮/擴展的效果,每個控件都平移到最底下控件的位置,然后消失。有時候我們的需求就是這樣,不要求將控件全部移出屏幕,只移到某個指定位置,然后消失之類的。如果是移出屏幕,那么距離很容易設定,但像這種情況下,我們要如何去設置每個控件應該平移多長的距離呢?

很多博客,在對屬性動畫介紹時,給出的示例代碼都是簡單的設置某個具體的數值,然后讓我們看效果。但這里還能繼續用寫死的固定值嗎,顯然不行,那么就需要我們在代碼中動態的來計算兩個控件之間的距離,然后再來確定控件應該平移的距離。

經過一番查找,題主找到可以用View.getLocationOnScreen()這個方法來實現。

    /**
     * 計算兩個view的距離
     * @param v1
     * @param v2
     * @return 返回new int[2], [0]橫坐標距離,[1]縱坐標的距離
     */
    private int[] calculateWidgetsDistance(View v1, View v2){
        int[] location1 = new int[2];
        int[] location2 = new int[2];
        int[] ret = new int[2];

        v1.getLocationOnScreen(location1);
        v2.getLocationOnScreen(location2);

        ret[0] = Math.abs(location1[0] - location2[0]);
        ret[1] = Math.abs(location1[1] - location2[1]);
        return ret;
    }

2、setTranslationX(float translationX) 參數值的含義

如果我們使用ValueAnimator來實現動畫效果,那么我們就需要接觸到setTranslationX()這類方法了,如下:

        ValueAnimator animator = ValueAnimator.ofFloat(mView.getTranslationY(),300.0f);
           animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    mView.setTranslationY(value);
                }
         });
       animator.setDuration(1000);
       animator.start();

那么好,問題來了。上面動畫的效果是什么?或者說 300.0f代表的是什么含義?

先來說說動畫的效果,是將mView從當前位置,沿Y軸平移到Y坐標300的地方?還是從當前位置沿Y正方向平移300?我們看下效果是什么:

好像是沿Y平移了300,那么真的是這樣嗎?如果上面代碼的效果表示的意思真是從當前位置沿Y平移300,那么當我們再次點擊按鈕時,應該繼續往下移300,不斷的點擊就不斷的往下移才對,但很明顯,從上圖中我們看出,當再次點擊時沒有任何動畫效果了。所以,上面代碼的動畫效果顯然不是沿Y平移300.

那么到底是什么效果呢?我們來將代碼稍微做些改動,先復制上面代碼,然后把300.0f改成200.0f,然后把復制的這個動畫綁定到其他按鈕(如下圖的FAB)上,這樣當我們先點擊FAB,再點擊按鈕本身,也就是先啟動平移200f動畫,再啟動平移300f的動畫。看看會有什么效果:

注意看上圖里的點擊順序,為了更方便講解,我們這里標好步驟:

  1. 點擊FAB時,控件往下平移一段距離
  2. 再點擊控件本身時,控件繼續往下平移一段距離,但比第一次平移的距離短
  3. 然后不斷點擊按鈕本身時,沒任何動畫效果
  4. 但是當再點擊FAB時,按鈕往上平移了
  5. 此時再點擊按鈕本身時,咦!發現有效果了,往下平移了
  6. 然后再點擊按鈕本身發現又沒任何效果了。但是再點擊FAB時,按鈕又往上平移了!發現沒有,當按鈕處於最底時,點擊FAB會將按鈕返回到第2個步驟了。

我稍微的對上面那圖做些備注,你們就很容易明白為什么是這個動畫效果,以及最初那幾個問題(300.0f代表什么含義)。

明白了沒有,300.0f表示的是相對於控件最初最初位置的一個距離,因為這里是Y軸平移,所以上面那代碼的動畫效果就是將mView控件從當前位置,沿Y軸平移到距離控件最初位置300的地方

所以,當我們改動代碼后才會有那個效果,因為點擊FAB,是將控件平移到距離最初起始位置為200的地方。然后再點擊按鈕本身時,代碼意思是將控件從當前位置平移到距離最初位置300的地方,但此時控件的位置並不是在最初的位置,而是已經經過一次平移,處於距離最初位置200的地方,當前控件要平移到300的地方,只需要再平移100就夠了。所以第二次控件下移的距離才會比第一次短。之后的效果就不要我再來講解了吧,記住300.f和200.0f都是相對於最初位置的距離,然后就可以很好的理解上圖的動畫了。

花這么多力氣說這個,是因為題主覺得,對於初學者來說,要確切的理解參數的含義,這樣才可以根據自己想要實現的動畫效果來計算需要傳遞進去的數值是多少。

好了,如果我們現在要實現這樣一個動畫效果,讓控件從當前位置沿Y軸平移到距離最初位置200的地方,那么代碼該怎么寫?

    ValueAnimator animator = ValueAnimator.ofFloat(mView.getTranslationY(),200.0f);
    ...

現在再來實現,很簡單,對吧。那么,再來,如果我們要實現,讓控件從當前位置沿Y軸平移200呢?

   ValueAnimator animator = ValueAnimator.ofFloat(mView.getTranslationY() , mView.getTranslationY() + 200.0f );
   ... 

怎么樣,想對了嗎。注意這里的需求是要相對於當前位置移動200,所以數值要怎么計算明白了吧。

理解了參數的含義,想要實現各種動畫效果就更有可能了。以上,均為題主學習中碰到的問題和自己的理解,如果有錯誤的地方,還望告知,不然誤導了別人可就不好了。

ObjectAnimator

題主是先接觸的ValueAnimator,然后才接觸ObjectAnimator的,基本的動畫效果用這兩個都能實現,而且ObjectAnimator實現起來,比ValueAnimator方便多了,反正題主現在是喜歡用ObjectAnimator就是了。

給你們看下,上面貼出來的代碼實現的動畫效果,用ObjectAnimator該怎么寫:

       ObjectAnimator animator = ObjectAnimator.ofFloat(mView,"translationY",mView.getTranslationY(),300.0f); 
       animator.setDuration(1000);
       animator.start();

一句代碼就搞定,簡單多了。雖然簡單,但也有幾點需要注意的,數值的確定問題跟上面一樣,上面理解了這里就可以直接用了,就不再多說了。

那么,就只剩下第二個參數"translationY"這個問題了。它的作用就是指定要實現的是哪個動畫屬性,說白點,屬性動畫就是通過不斷修改屬性值來達到效果的,這點在上面分析的第二點給出的代碼上也可以很容易看出來。

那么,這個屬性值到底有哪些,這個字符串的參數可以傳遞哪些進去?不知道有沒有初學者跟題主一樣,剛接觸時都有這個困惑。

去網上查找,你會發現,很多大神都給列舉出了其他一些取值,比如"alpha"、"rotationX/Y"等等,那么這些值是從哪來的呢?可以看一看郭神的這一篇。這里就稍微提一下,如果你突然忘記某個動畫單詞該怎么拼,或者不知道它支不支持使用這個方法,可以利用AS的查看源碼方式到View里面去查找一下setXXX()和getXXX()方法,如果有,則支持。

Github

最后附上Demo源代碼地址,有興趣可以看看,代碼很粗糙,只是為了理解怎么用而寫的,大家就忽略掉這個問題吧。

AnimatorDemo:https://github.com/woshidasusu/AnimatorDemo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM