Android系統編程入門系列之介面Activity響應多元的屬性動畫
- 2021 年 7 月 30 日
- 筆記
在響應絲滑動畫一篇文章中,分別介紹了作用於普通視圖、繪製視圖的繪製對象、和介面這三種對象的動畫效果,但是都有一些使用的局限性。比如這些動畫都只是以螢幕上繪製更新的方式繪製動畫,並沒有真實改變作用對象的實際位置或屬性,這種問題在視圖動畫中尤為明顯,在沒有特別設置時,動畫結束後的視圖狀態會還原到動畫前,也就是說動畫中及動畫後的視圖對象是沒有保存動畫中用到的一些屬性的。這種情況就需要使用本文所介紹的屬性動畫了。
屬性動畫本質是對某個對象的屬性提供一組變化更新的屬性值,他的作用對象不僅可以是視圖和介面,也可以是任何具有上述需求的對象類。在Android3.0 API 11開始的AndroidSDK版本中,定義了android.animation.Animator類作為抽象父類來描述屬性動畫的結構,並提供了android.animation.ValueAnimator作為只變化屬性值的屬性動畫類、android.animation.ObjectAnimator可以變化屬性值並更新到對象屬性的屬性動畫類、和android.animation.AnimatorSet包含多個屬性動畫集合的屬性動畫類。
與普通動畫類似,屬性動畫同樣可以在資源文件中靜態聲明,也可以在程式碼中動態聲明,但是由於其作用對象可以是任何對象,而且屬性動畫的優勢在於為作用對象的屬性提供一組變化的屬性值,所以屬性動畫只能在需要綁定作用對象的程式碼位置動態使用。由於靜態聲明的屬性動畫可以針對多個對象使用,在開發過程中推薦使用靜態聲明+動態使用的方式。
只變化屬性值的屬性動畫類
ValueAnimator
作為最核心的屬性動畫類,可以調用ValueAnimator.ofArgb(int... values)
、ValueAnimator.ofFloat(float... values)
、ValueAnimator.ofInt(int... values)
、ValueAnimator.ofObject(TypeEvaluator evaluator, Object... values)
系列靜態方法,獲取初始化後的實例化對象。其中的參數 values 是可變長參數,作為可變化屬性值的範圍區間。而參數 evaluator 是android.animation.TypeEvaluator估值器介面的實現類,用以計算估計屬性值的具體變化數值的類。而AndroidSDK中已經定義了上述系列靜態方法前三種類型對應的估值器子類,分別是android.animation.ArgbEvaluator、android.animation.FloatEvaluator、android.animation.IntEvaluator,除此之外還有計算二維坐標系的估值器android.animation.PointFEvaluator和計算矩形坐標的估值器android.animation.RectEvaluator。另外,在實際開發中針對作用對象要變化的屬性值類型不同,也可以自定義實現TypeEvaluator
介面的估值器。
這裡提到的ArgbEvaluator
是用以計算顏色的 ARGB 色值估值器,與Android系統定義的螢幕坐標類似,這裡的 ARGB 色值也是一套系統顏色規範。在Java中int類型是用4個位元組存儲的,這4個位元組按順序從大端到小端,剛好分別表示Alpha(顏色值中的透明度),Red(顏色值中的紅色值),Green(顏色值中的綠色值),Blue(顏色值中的藍色值),每個位元組的數值可以表示範圍是[ 0x0, 0xFF ],所以用十六進位表示顏色值中的純紅色為 0xFFFF0000 ,純黑色為 0xFF000000 ,純白色為 0xFFFFFFFF ,而完全透明色為 0x00000000 到 0x00FFFFFF 之間的任一值。也可以藉助android.graphics.Color類使用已經定義的顏色值和系統顏色規範的相關方法。
在創建ValueAnimator
實例化對象後,
可以調用setDuration(long duration)
設置完成一次動畫效果的持續時間,單位為 ms 毫秒。
調用setRepeatCount(int value)
設置完成一次動畫效果後的重複次數,默認 value = ValueAnimator.INFINITE 為無限循環。
調用setRepeatMode(int value)
設置在完成一次動畫效果後重複時的動畫效果,其 value 只能為
ValueAnimator.RESTART 表示從頭開始重新完成一次一模一樣的動畫效果,
和ValueAnimator.REVERSE 表示從上次動畫結尾開始完成一次倒放的動畫效果。
調用 setInterpolator(TimeInterpolator value)
設置動畫效果的時間插值器。與上面的估值器定義結構類似,參數 value 是android.animation.TimeInterpolator插值器介面的實現類,用以確定每次更新動畫效果的時間。同樣的,AndroidSDK已經定義了一系列插值器,包括但不限於持續加速插值器android.view.animation.AccelerateInterpolator、持續減速插值器android.view.animation.DecelerateInterpolator、線性勻速插值器android.view.animation.LinearInterpolator等,同樣在實際開發中針對動畫效果展示時間進度,也可以自定義實現TimeInterpolator
介面的插值器。
最終在需要啟動當前屬性動畫的位置調用start()
即開始播放當前動畫效果,如果不想在調用屬性動畫的啟動方法後立即執行相關動畫效果,可以在啟動方法之前調用setStartDelay(long startDelay)
設置延時動畫的延長時間,單位是 ms 毫秒。
ValueAnimator
是根據TypeEvaluator
估值器來更新屬性值的,而更新的時間則是由TimeInterpolator
插值器決定的,那麼怎麼才能拿到每次更新後的屬性值呢?這裡就可以用調用ValueAnimator
對象的addUpdateListener(ValueAnimator.AnimatorUpdateListener listener)
方法添加屬性動畫更新監聽,在AnimatorUpdateListener類中重寫onAnimationUpdate(ValueAnimator animation)
方法,該方法中的參數animation即更新後的屬性動畫對象,通過調用animation.getAnimatedValue()
來接收每次更新後的屬性值,並可以將更新後的屬性值賦值給需要屬性動畫的對象中。
也可以在資源文件中靜態定義屬性動畫,在 res/animator 目錄下,定義xml格式的屬性動畫資源文件,該資源文件內以<animator />
為根標籤,其中可以設置android:duration
作為完成一次動畫效果的持續時間等一系列屬性,與程式碼中動態設置的相關方法類似。之後在程式碼使用位置載入該資源文件,通過調用AnimatorInflater.loadAnimator(Context context, int id)
的靜態方法,參數context作為調用位置所在的上下文環境,參數id則是要載入的屬性動畫類型的資源文件名。將得到Animator
抽象類的返回結果,根據所載入資源文件中的根標籤名判斷,如果與<animator />
一致,則可將返回的Animator
抽象類直接轉換為ValueAnimator
類型的對象。
可變化屬性值並更新到對象屬性的屬性動畫類
ObjectAnimator
作為ValueAnimator
的子類,定義和使用方式都有類似的地方,只是ObjectAnimator
類中封裝了屬性動畫的更新監聽方法,因此只要綁定對象及其要變化的屬性,在屬性動畫每次變化屬性值時,都會主動將屬性值更新到綁定對象的相關屬性上。
因此在初始化實例對象時需要調用ofArgb(Object target, String propertyName, int... values)
、ofFloat(Object target, String xPropertyName, String yPropertyName, Path path)
、ofInt(T target, Property<T, Integer> property, int... values)
、ofObject(T target, Property<T, V> property, TypeConverter<PointF, V> converter, Path path)
等系列靜態方法。
其中參數 target 即為要綁定的動畫效果作用對象;
參數 propertyName 是 target 對象中的某個屬性,而且該屬性必須要有符合駝峰命名規則的 get 和 set 方法;
參數 values 仍然作為可變化屬性值的範圍區間;
參數 path 作為android.graphics.Path類,則表示一段動畫效果的執行路徑,以此替換參數 values 表示的單一變化區間;
參數 property 作為android.util.Property抽象類,同樣描述某種屬性類型,以此替換String
類型的參數 propertyName ;
參數 converter 作為android.animation.TypeConverter抽象類,與上文的參數 property 同時使用,當 property 中聲明的屬性類型與實際變化更新的屬性值不一致時,使用參數 converter 所表示的強制類型轉換方式。
在創建實例化對象後,ObjectAnimator
有與ValueAnimator
一致的setXXX()
和getXXX()
系列方法,另外還有setTarget(Object target)
方法可以直接綁定要變化屬性值的目標對象,同時有setPropertyName(String propertyName)
和setProperty(Property property)
兩種調用方法,都能實現對目標對象中的目標屬性的綁定。
最後仍然是在需要啟動當前屬性動畫的位置調用start()
開始播放當前動畫效果。
在資源文件中靜態定義時,同樣在 res/animator 目錄下,定義xml格式的屬性動畫資源文件,不過該資源文件內根標籤為<objectAnimator />
以標記關聯對象的屬性動畫,其中的屬性設置不僅與只變化屬性值的ValueAnimator
對應的<animator />
標籤中的屬性一致,還可單獨設置android:propertyName
綁定屬性名稱。之後同樣可以在程式碼中調用AnimatorInflater.loadAnimator(Context context, int id)
靜態方法載入當前屬性動畫資源文件,同樣地,針對得到的Animator
抽象類的返回結果,根據所載入資源文件中的根標籤名判斷,如果與<objectAnimator />
一致,則可將返回的Animator
抽象類直接轉換為ObjectAnimator
類型的對象。
包含多個屬性動畫集合的屬性動畫類
SetAnimator
是將一系列上述單獨的屬性動畫組合起來的屬性動畫合集,其使用目的主要是為了講不同的屬性動畫按照同一條時間線整理播放,因此其相關方法主要與其中子動畫的播放順序相關。
通過直接創建SetAnimator()
構造方法可以獲得SetAnimator
實例化對象。
得到的對象調用playTogether(Animator... items)
方法可以在同一段時間內播放添加的子動畫,
調用playSequentially(Animator... items)
方法可以將其中的子動畫按照添加順序播放,
而這兩個系列方法中的可變長參數 items 即是要添加的系列子動畫對象。
也可以將得到的對象調用play(Animator anim)
方法,參數 anim 為添加的基本動畫,返回android.animation.AnimatorSet.Builder類型,可以調用該類的before(Animator anim)
方法設置針對基本動畫之前播放的動畫 anim 、調用該類的with(Animator anim)
方法設置與基本動畫同時播放的動畫 anim 、調用該類的after(Animator anim)
方法設置針對基本動畫之後播放的動畫 anim 、以及該類的after(long delay)
方法設置在基本動畫之後延時 delay 毫秒之後繼續播放之後動畫。
最後仍然是在需要啟動當前屬性動畫的位置調用start()
開始播放當前動畫效果。
在資源文件中靜態定義時,同樣在 res/animator 目錄下,定義xml格式的屬性動畫資源文件,在資源文件內根標籤為<set></set>
以標記為集合屬性動畫,該標籤內可以設置屬性android:ordering
,其值只能為默認的together
表示子動畫同時執行,或者為sequentially
表示子動畫按順序執行。在<set></set>
標籤內部,可以嵌入上述<animator />
或<objectAnimator />
兩種屬性動畫標籤。同樣可以在程式碼中調用AnimatorInflater.loadAnimator(Context context, int id)
靜態方法載入當前屬性動畫資源文件,同樣地,針對得到的Animator
抽象類的返回結果,根據所載入資源文件中的根標籤名判斷,如果與<set></set>
一致,則可將返回的Animator
抽象類直接轉換為AnimatorSet
類型的對象。