1. 程式人生 > >自定義控制元件ObjectAnimator基本使用

自定義控制元件ObjectAnimator基本使用

利用ObjectAnimator重寫的ofFloat方法如何實現一個動畫:

(改變透明度)


  1. publicstatic ObjectAnimator ofFloat(Object target, String propertyName, float... values)   
  • 第一個引數用於指定這個動畫要操作的是哪個控制元件
  • 第二個引數用於指定這個動畫要操作這個控制元件的哪個屬性
  • 第三個引數是可變長引數,這個就跟ValueAnimator中的可變長引數的意義一樣了,就是指這個屬性值是從哪變到哪。像我們上面的程式碼中指定的就是將textview的alpha屬性從0變到1再變到0;
下面我們再來看一下如何實現旋轉效果:
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果圖如下:

從程式碼中可以看到,我們只需要改變ofFloat()的第二個引數的值就可以實現對應的動畫; 
那麼問題來了,我們怎麼知道第二個引數的值是啥呢?

2、setter函式

我們再回來看構造改變rotation值的ObjectAnimator的方法
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,
    "rotation",0,180,0);  
TextView控制元件有rotation這個屬性嗎?沒有,不光TextView沒有,連它的父類View中也沒有這個屬性。那它是怎麼來改變這個值的呢?其實,ObjectAnimator做動畫,並不是根據控制元件xml中的屬性來改變的,而是通過指定屬性所對應的set方法來改變的。比如,我們上面指定的改變rotation的屬性值,ObjectAnimator在做動畫時就會到指定控制元件(TextView)中去找對應的setRotation()方法來改變控制元件中對應的值。同樣的道理,當我們在最開始的示例程式碼中,指定改變”alpha”屬性值的時候,ObjectAnimator也會到TextView中去找對應的setAlpha()方法。那TextView中都有這些方法嗎,有的,這些方法都是從View中繼承過來的,在View中有關動畫,總共有下面幾組set方法:

  1. //1、透明度:alpha
  2. publicvoid setAlpha(float alpha)  
  3. //2、旋轉度數:rotation、rotationX、rotationY
  4. publicvoid setRotation(float rotation)  
  5. publicvoid setRotationX(float rotationX)  
  6. publicvoid setRotationY(float rotationY)  
  7. //3、平移:translationX、translationY
  8. publicvoid setTranslationX(float translationX)   
  9. publicvoid setTranslationY(float translationY)  
  10. //縮放:scaleX、scaleY
  11. publicvoid setScaleX(float scaleX)  
  12. publicvoid setScaleY(float scaleY)  
可以看到在View中已經實現了有關alpha,rotaion,translate,scale相關的set方法。所以我們在構造ObjectAnimator時可以直接使用。 
在開始逐個看這些函式的使用方法前,我們先做一個總結: 
1、要使用ObjectAnimator來構造對畫,要操作的控制元件中,必須存在對應的屬性的set方法 
2、setter 方法的命名必須以駱駝拼寫法命名,即set後每個單詞首字母大寫,其餘字母小寫,即類似於setPropertyName所對應的屬性為propertyName 

下面我們就來看一下上面中各個方法的使用方法及作用。 
有關alpha的用法,上面已經講過了,下面我們來看看其它的 

(1)、setRotationX、setRotationY與setRotation

  • setRotationX(float rotationX):表示圍繞X軸旋轉,rotationX表示旋轉度數 
  • setRotationY(rotationY):表示圍繞Y軸旋轉,rotationY表示旋轉度數 
  • setRotation(float rotation):表示圍繞Z旋轉,rotation表示旋轉度數 
先來看看setRotationX的效果:
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

效果圖如下: 


從效果圖中明顯看出,textview的旋轉方法是圍繞X軸旋轉的,我們設定為從0度旋轉到270度再返回0度。 
然後再來看看setRotationY的使用方法與效果:
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationY",0,180,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

效果圖如下: 


從效果圖中明顯可以看出圍繞Y軸旋轉的。 
我們再來看看setRotation的用法與效果:
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,270,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

我們上面說了,setRotation是圍繞Z軸旋轉的,可能有些同學不理解什麼是Z軸,我們來看一張圖: 


從這張圖中,綠色框部分表示手機螢幕,很明顯可以看出Z軸就是從螢幕左上角原點向外伸出的一條軸。這樣,我們也就可以理解圍繞Z軸旋轉,為什麼是這樣子轉了。 

(2)、setTranslationX與setTranslationY

  • setTranslationX(float translationX) :表示在X軸上的平移距離,以當前控制元件為原點,向右為正方向,引數translationX表示移動的距離。 
  • setTranslationY(float translationY) :表示在Y軸上的平移距離,以當前控制元件為原點,向下為正方向,引數translationY表示移動的距離。 
我們先看看setTranslationX的用法:
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationX"0200, -200,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果圖如下: 

所以,我們上面在構造動畫時,指定的移動距離是(0, 200, -200,0),所以控制元件會從自身所有位置向右移動200畫素,然後再移動到距離原點-200的位置,最後回到原點; 
然後我們來看看setTranslateY的用法:

  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationY"0200, -100,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果圖如下:(為了方便看到效果,將textview垂直居中) 

同樣,移動位置的座標也都是以當前控制元件所在位置為中心點的。所以對應的移動位置從原點移動向下移動200畫素,然後再移動到向下到距原點200畫素的位置,最後再回到(0,0)從效果圖中很明顯可以看出來。 
從上面可以看出:每次移動距離的計算都是以原點為中心的;比如初始動畫為ObjectAnimator.ofFloat(tv, “translationY”, 0, 200, -100,0)表示首先從0移動到正方向200的位置,然後再移動到負方向100的位置,最後移動到原點。 

(3)、setScaleX與setScaleY

  • setScaleX(float scaleX):在X軸上縮放,scaleX表示縮放倍數 
  • setScaleY(float scaleY):在Y軸上縮放,scaleY表示縮放倍數 
我們來看看setScaleX的用法:
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleX"031);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果圖如下: 

在效果圖中,從0倍放大到3倍,然後再還原到1倍的原始狀態。 
然後再來看看setScaleY的用法

  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY"031);  
  2. animator.setDuration(2000);  
  3. animator.start();  
為了更好的看到效果,我把textview垂直居中了,效果圖如下: 

原始碼在文章底部給出  好了,到這裡有關View中自帶的set函式講完了,我們來看看ObjectAnimator是如何實現控制元件動畫效果的。

3、ObjectAnimator動畫原理

我們先來看張圖: 


在這張圖中,將ValueAnimator的動畫流程與ObjectAnimator的動畫流程做了個對比。 
可以看到ObjectAnimator的動畫流程中,也是首先通過加速器產生當前進度的百分比,然後再經過Evaluator生成對應百分比所對應的數字值。這兩步與ValueAnimator是完全一樣的,唯一不同的是最後一步,在ValueAnimator中,我們要通過新增監聽器來監聽當前數字值。而在ObjectAnimator中,則是先根據屬性值拼裝成對應的set函式的名字,比如這裡的scaleY的拼裝方法就是將屬性的第一個字母強制大寫後,與set拼接,所以就是setScaleY。然後通過反射找到對應控制元件的setScaleY(float scaleY)函式,將當前數字值做為setScaleY(float scale)的引數將其傳入。 
這裡在找到控制元件的set函式以後,是通過反射來呼叫這個函式的,有關反射的使用大家可以參考《夯實JAVA基本之二 —— 反射(1):基本類周邊資訊獲取》 
這就是ObjectAnimator的流程,最後一步總結起來就是呼叫對應屬性的set方法,將動畫當前數字值做為引數傳進去。 
根據上面的流程,這裡有幾個注意事項: 
(1)、拼接set函式的方法:上面我們也說了是首先是強制將屬性的第一個字母大寫,然後與set拼接,就是對應的set函式的名字。注意,只是強制將屬性的第一個字母大寫,後面的部分是保持不變的。反過來,如果我們的函式名命名為setScalePointX(float ),那我們在寫屬性時可以寫成”scalePointX”或者寫成“ScalePointX”都是可以的,即第一個字母大小寫可以隨意,但後面的部分必須與set方法後的大小寫保持一致。 
(2)、如何確定函式的引數型別:上面我們知道了如何找到對應的函式名,那對應的引數方法的引數型別如何確定呢?我們在講ValueAnimator的時候說過,動畫過程中產生的數字值與構造時傳入的值型別是一樣的。由於ObjectAnimator與ValueAnimator在插值器和Evaluator這兩步是完全一樣的,而當前動畫數值的產生是在Evaluator這一步產生的,所以ObjectAnimator的動畫中產生的數值型別也是與構造時的型別一樣的。那麼問題來了,像我們的構造方法。

  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY"031);  
由於構造時使用的是ofFloat函式,所以中間值的型別應該是Float型別的,所以在最後一步拼裝出來的set函式應該是setScaleY(float xxx)的樣式;這時,系統就會利用反射來找到setScaleY(float xxx)函式,並把當前的動畫數值做為引數傳進去。 
那問題來了,如果沒有類似setScaleY(float xxx)的函式,我們只實現了一個setScaleY(int xxx)的函式怎麼辦?這裡雖然函式名一樣,但引數型別是不一樣的,那麼系統就會報一個錯誤: 

意思就是對應函式的指定引數型別沒有找到。 
(3)、呼叫set函式以後怎麼辦?從ObjectAnimator的流程可以看到,ObjectAnimator只負責把動畫過程中的數值傳到對應屬性的set函式中就結束了,注意傳給set函式以後就結束了!set函式就相當我們在ValueAnimator中新增的監聽的作用,set函式中的對控制元件的操作還是需要我們自己來寫的。

那我們來看看View中的setScaleY是怎麼實現的吧:

  1. /**