Android 動畫深入分析
Android 的動畫可以分為三種:View 動畫、幀動畫和屬性動畫。
View 動畫
View 動畫的作用物件是 View,它支援四種動畫效果:平移動畫、縮放動畫、旋轉動畫和透明度動畫。幀動畫也屬於 View 動畫,只是表現形式不一樣。
View 動畫的種類
- View 的四種動畫效果對應著 Animation 的四個子類:TranslateAnimation、ScaleAnimation、RotateAnimation 和 AlphaAnimation。
- View 動畫既可以通過 XML 來定義,也可以通過程式碼來動態建立,建議採用 XML 的方式,因為可讀性更好。
名稱 | 標籤 | 子類 | 效果 |
---|---|---|---|
平移動畫 | <translate> | TranslateAnimation | 移動 View |
縮放動畫 | <scale> | ScaleAnimation | 放大或縮小 View |
旋轉動畫 | <rotate> | RotateAnimation | 旋轉 View |
透明度動畫 | <alpha> | AlphaAnimation | 改變 View 的透明度 |
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true"// 動畫結束後 View 是否停留在結束位置 android:interpolator="@anim/interpolator_resourse" // 動畫集合所採用的插值器 android:shareInterpolator="true"// 集合中的動畫是否和集合共享同一個插值器> <alpha// 透明度動畫 android:fromAlpha="1.0"// 透明度的起始值 android:toAlpha="0.0"// 透明度的結束值 android:duration="10000"// 動畫持續時間/> <rotate // 旋轉動畫 android:fromDegrees="300"// 旋轉開始時的角度 android:toDegrees="-360"// 旋轉結束時的角度 android:pivotX="10%"// 旋轉軸點的 X 座標 android:pivotY="100%"// 旋轉軸點的 Y 座標 /> <scale// 縮放動畫 android:fromXScale="0.0"// 水平方向縮放的起始值 android:toXScale="1.5"// 水平方向縮放的結束值 android:fromYScale="0.0"// 豎直方向縮放的起始值 android:toYScale="1.5"// 豎直方向縮放的結束值 android:pivotX="50%"// 縮放軸點的 X 座標 android:pivotY="50%"// 縮放軸點的 Y 座標 /> <translate// 平移動畫 android:fromXDelta="320"// X 座標的起始值 android:toXDelta="0"// X 座標的結束值 android:fromYDelta="480"// Y 座標的起始值 android:toYDelta="0"// Y 座標的結束值 /> </set>
-
應用 XML 動畫:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation); view.startAnimation(animation);
-
程式碼建立動畫:
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1); alphaAnimation.setDuration(300) view.startAnimation(alphaAnimation);
自定義 View 動畫
繼承 Animation 抽象類,然後重寫它的 initialize 和 applyTransformation 方法,在 initialize 方法中做一些初始化的工作,在 applyTransformation 方法中進行相應的矩陣變換即可。Ps. 很多時候使用 Camera 來簡化矩陣變化過程。
幀動畫
幀動畫是順序播放一組預先定義好的圖片,類似於電影播放。系統提供了一個 AnimationDrawable 來使用幀動畫。
幀動畫 XML 中使用
View 動畫的特殊使用場景
LayoutAnimation
LayoutAnimation 作用於 ViewGroup,為 ViewGroup 指定一個動畫,它的子元素出場時都會具有這種動畫效果。
一般遵循如下步驟:
-
定義 LayoutAnimation:
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="0.5"// 表示子元素開始動畫的時間延遲,需要乘以 Duration android:animationOrder="reverse"// 表示子元素動畫的順序,normal 表示順序顯示;reverse 表示排在後面先開始動畫;random 表示隨機 android:animation="@anim/anim_item"// 為子元素指定具體的入場動畫 />
-
為子元素指定具體的入場動畫:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:interpolator="@android:anim/accelerate_interpolator" android:shareInterpolator="true" > <alpha android:fromAlpha="0.0" android:toAlpha="1.0" /> <translate android:fromXDelta="500" android:toXDelta="0" /> </set>
-
為 ViewGroup 指定
android:layoutAnimation="@anim/anim_layout"
屬性。當然也可以使用程式碼來設定:Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item); LayoutAnimationController controller = new LayoutAnimationController(animation); controller.setDelay(0.5f); controller.setOrder(LayoutAnimationController.ORDER_NORMAL); listView.setLayoutAnimation(controller);
Activity 的切換效果
使用overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
來自定義切換效果,注意:這個方法必須在startActivity(intent)
或者finish()
之後呼叫才能生效。
屬性動畫
屬性動畫是 API 11 新加入的特性。
使用屬性動畫
屬性動畫可以多任意物件的屬性進行動畫而不僅僅是 View,動畫預設時間間隔300ms,預設幀率 10ms/幀。比較常用的幾個動畫類是:ValueAnimator、ObjectAnimator 和 AnimatorSet。
-
幾個示例程式碼:
// 改變一個物件 view 的 translationY 屬性,讓其沿著 Y 軸向上平移一段距離。 ObjectAnimator.ofFloat(view, "translationY", -getActionBar().getHeight()).start(); ... // 動態改變一個物件 view 的背景色。 ValueAnimator colorAnim = ObjectAnimator.ofInt(view, "backgroundColor", 0xFFFF8080, 0xFF8080FF); colorAnim.setDuration(3000); colorAnim.setEvaluator(new ArgbEvaluator()); colorAnim.setRepeatCount(ValueAnimator.INFINITE); colorAnim.setRepeatMode(ValueAnimator.REVERSE); colorAnim.start(); ... // 動畫集合 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( ObjectAnimator.ofFloat(view, "translationX", 0, 90), ObjectAnimator.ofFloat(view, "translationY", 0, 90) ); animatorSet.setDuration(1000).start();
-
使用 XML 來定義屬性動畫
<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="sequentially" > <objectAnimator android:duration="2000" android:propertyName="translationX" android:valueFrom="-500" android:valueTo="0" android:valueType="floatType" > </objectAnimator> <set android:ordering="together" > <objectAnimator android:duration="3000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" android:valueType="floatType" > </objectAnimator> <set android:ordering="sequentially" > <objectAnimator android:duration="1500" android:propertyName="alpha" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" > </objectAnimator> <objectAnimator android:duration="1500" android:propertyName="alpha" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" > </objectAnimator> </set> </set> </set>
最後通過 Java 程式碼來使用屬性動畫:
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file); animator.setTarget(view); animator.start();
理解插值器和估值器
- TimeInterpolator 翻譯為時間插值器,它的作用是根據時間流逝的百分比來計算出當前屬性值改變的百分比,系統預置有 LinearInterpolator、AccelerateInterpolator 等等插值器。
- TypeEvaluator 翻譯為型別估值演算法,也叫估值器,它的作用是根據當前屬性改變的百分比來計算改變後的屬性值,系統預置有 IntEvaluator、FloatEvaluator 和 ArgbEvaluator 等估值器。
- 自定義插值器需要實現 Interpolator 或 TimeInterpolator 介面;自定義估值器需要實現 TypeEvaluator 介面。
屬性動畫的監聽器
屬性動畫主要提供了兩個介面用於監聽:AnimatorListener 和 AnimatorUpdateListener。
onAnimationUpdate
對任意屬性做動畫
-
屬性動畫要求動畫作用的物件提供該屬性的 get 和 set 方法,要同時滿足以下兩個條件:
-
object 必須要提供
setAbc
的方法,如果動畫的時候沒有傳遞初始值,那麼還要提供getAbc
的方法,因為系統要去取 abc 屬性的初始值,如果不滿足這個條件,程式會 Crash。 -
object 的
setAbc
的方法對屬性 abc 所做的改變必須能通過某種方式反映出來,比如會帶來 UI 的改變,如果不滿足這個條件,動畫將會沒有效果,但程式不會Crash。
-
object 必須要提供
-
屬性動畫有時沒有效果的解決辦法:
- 給你的物件加上 set 和 get 方法,如果你有許可權的話
-
用一個類來包裝原始物件,間接為期提供 set 和 get 方法
private static class ViewWrapper{ private View target; public ViewWrapper(View target){ this.target = target; } public int getWidth(){ return target.getWidth(); } public void setWidth(int width){ target.getLayoutParams().width = width; target.requestLayout(); } }
-
採用 ValueAnimator,監聽動畫過程,自己實現屬性的改變
屬性動畫的工作原理
屬性動畫要求動畫作用的物件提供該屬性的 set 方法,屬性動畫根據你傳遞的該屬性的初始值和最終值,以動畫的效果多次去呼叫 set 方法。每次傳遞給 set 方法的值都不一樣,確切來說是隨著時間的推移,所傳遞的值越來越接近最終值。如果動畫的時候沒有傳遞初始值,那麼還要提供 get 方法,因為系統要去獲取屬性的初始值。
使用動畫的注意事項
view.clearAnimation()
本章節配套原始碼ofollow,noindex">戳我