第七章 Android動畫深入分析 Android的動畫分為三種:View動畫,幀動畫,屬性動畫。幀動畫屬於View動畫。 7.1 View動畫 View動畫的作用對象是View,共有四種動畫效果:平移(Translate),縮放(Scale),旋轉(Rotate),透明度(Al...
第七章 Android動畫深入分析
Android的動畫分為三種:View動畫,幀動畫,屬性動畫。幀動畫屬於View動畫。
7.1 View動畫
View動畫的作用對象是View,共有四種動畫效果:平移(Translate),縮放(Scale),旋轉(Rotate),透明度(Alpha)。
7.1.1 View動畫的種類
名稱 | 標簽 | 子類 | 效果 |
平移 | <translate> | TranslateAnimation | 移動View |
縮放 | <scale> | ScaleAnimation | 放大或縮小View |
旋轉 | <rotate> | RotateAnimation | 旋轉View |
透明度 | <alpha> | AlphaAnimation | 改變View的透明度 |
View動畫的保存路徑:res/anim/filename.xml。XML格式語法如下:
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/interpolator_resource"
android:shareInterpolator="true|false">
<alpha
android:fromAlpha="float"<!-- 透明度起始值-->
android:toAlpha="float"/><!-- 透明度結束值-->
<scale
android:fromXScale="float"<!--水平方向縮放起始值 -->
android:toXScale="float"<!--水平方向縮放結束值 -->
android:fromYScale="float"<!--垂直方向縮放起始值 -->
android:toYScale="float"<!--垂直方向縮放結束值 -->
android:pivotX="float"<!--縮放軸點x坐標 -->
android:pivotY="float"/><!--縮放軸點y坐標 -->
<translate
android:fromXDelta="float"<!--x的起始位置-->
android:fromYDelta="float"<!--y的起始位置-->
android:toXDelta="float"<!--x的結束位置-->
android:toYDelta="float"/><!--y的結束位置-->
<rotate
android:fromDegrees="float"<!--起始角度 -->
android:toDegrees="float"<!-- 結束角度-->
android:pivotX="float"<!-- 旋轉軸點x坐標 -->
android:pivotY="float"/><!-- 旋轉軸點y坐標-->
<set>
...
</set>
</set>
<set>標簽表示動畫集合,對應AnimationSet類,內部還可以嵌套其他動畫集合。
android:interpolator 插值器規定動畫已怎樣的速度運行,預設為加速減速插值器。
android:shareInterpolator 集合中的動畫是否和集合共用同一個插值器。
android:duration 動畫持續時間
android:fillAfter 動畫結束後View是否停留在結束位置。
<scale>、<rotate>中軸點預設情況下是View的中心點(有待驗證貌似是左上角)。
在代碼中載入xml中定義的動畫:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.view1);
button.startAnimation(animation);
使用Animation的setAnimationListener方法可以給View動畫添加監聽。
7.1.2 自定義View動畫
原理:繼承Animation這個抽象類,然後重寫它的initialize和applyTransformation方法,在initialize中做初始化,在applyTransformation中進行相應的矩陣變換即可。通常採用camera來簡化矩陣變換的過程。自定義View動畫的過程主要就是矩陣變換的過程。例子可參考APIDEMO中的Rotate3dAnimation效果。
7.1.3 幀動畫
幀動畫其實就是順序播放一組預先定義好的圖片。通過AnimationDrawable來使用幀動畫。XML格式語法如下:
<?xml version="1.0" encoding="utf-8" ?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true|false">
<item android:drawable="@mipmap/ic_launcher" android:duration="500"/>
<item android:drawable="@mipmap/ic_launcher" android:duration="500"/>
<item android:drawable="@mipmap/ic_launcher" android:duration="500"/>
</animation-list>
使用時直接作為View的背景並通過Drawable來播放即可。
button.setBackgroundResource(R.drawable.view2);
AnimationDrawable drawable=(AnimationDrawable)button.getBackground();
drawable.start();
7.2 View動畫的特殊使用場景
7.2.1 LayoutAnimation
作用於ViewGroup,為ViewGroup指定一個動畫,這樣當它的子元素出場時都會具有這種動畫效果。
步驟:
(1)定義LayoutAnimation
<?xml version="1.0" encoding="utf-8" ?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/anim_item"/>
android:delay 子元素開始動畫的時間延遲,例如子元素設置duration為200ms,則0.5表示每個子元素都需要延遲100ms開能開始播放動畫,即第一個經過100ms開始播放,第二個就得經過200ms開始播放,第三個就得經過300ms開始播放,以此類推。
android:animationOrder 子元素動畫順序,normal(順序顯示),reverse(逆向顯示),random(隨機)。
(2)為子元素指定動畫
<?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:toYDelta="0" />
</set>
(3)為ViewGroup指定android:layoutAnimation屬性
android:layoutAnimation="@anim/anim_layout"
或者通過LayoutAnimationController來為ViewGroup指定動畫。
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller=new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
linearlayout.setLayoutAnimation(controller);
7.2.2 Activity的切換效果
使用overridePendingTransition(int enterAnim, int exitAnim)方法,註意這個方法必須在startActivity或者finish之後被調用才能生效。
enterAnim——Activity被打開時的動畫
exitAnim——Activity退出時的動畫
啟動Activity:
Intent intent =new Intent(this,TestActivity.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);
}
7.3 屬性動畫
API等級必須大於等於11,存放路徑為res/animator/目錄下,屬性動畫可以對任何對象做動畫,常見的有ValueAnimator、ObjectAnimator。
7.3.1 使用屬性動畫
屬性動畫預設時間間隔為300ms,預設幀率為10ms/幀,可以達到在一個時間間隔內完成對象從一個屬性值到另一個屬性值的改變。如果想要屬性動畫相容低版本系統,需要使用NineOldAndroids這個開源動畫庫。
舉例說明如何使用屬性動畫:
(1)改變一個對象的translationY屬性,讓其沿著Y軸向上平移一段距離:它的高度。
ObjectAnimator.ofFloat(myObject,"translationY",-myObject.getHeight());
(2)改變一個View的背景色,讓其背景色在3秒內實現用0xFFFF8080到0xFF8080FF的漸變,動畫無限迴圈並加反轉效果。
ValueAnimator colorAnim=ObjectAnimator.ofInt(this,"backgroundColor",0xFFFF8080,0xFF8080FF);
colorAnim.setDuration(3000);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.start();
屬性動畫的XML格式語法如下:
<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially|together"><!--together:子動畫同時播放。sequentially:自動化按照先後順序依次播放-->
<objectAnimator
android:duration="int"<!--動畫時長-->
android:propertyName="string"<!--屬性名稱-->
android:repeatCount="int"<!--重覆次數-->
android:repeatMode="restart|reverse"<!--重覆模式-->
android:startOffset="int"<!--延遲時間-->
android:valueFrom="float|int|color"<!--屬性起始值-->
android:valueTo="float|int|color"<!--屬性結束值-->
android:valueType="colorType|intType|floatType|pathType" /><!--屬性類型-->
<animator
android:duration="int"
android:repeatCount="int"
android:repeatMode="restart|reverse"
android:startOffset="int"
android:valueFrom="float|int|color"
android:valueTo="float|int|color"
android:valueType="colorType|intType|floatType|pathType" />
</set>
android:repeatCount 動畫的迴圈次數,預設為0,-1為無限迴圈;
android:repeatMode repeat:連續重覆;reverse:逆向重覆(第一次播放完後,第二次倒著播放,第三次在重頭開始播如此反覆)。
在XML中定義好屬性動畫後在java代碼中就可以使用了
AnimatorSet set=(AnimatorSet) AnimatorInflater.loadAnimator(context,R.anim.property_animator);
set.setTarget(button);
set.start();
實際開發中建議使用代碼來實現屬性動畫,不要使用xml的方式。
7.3.2 理解插值器和估值器
插值器:根據時間流逝的百分比來計算出當前屬性值改變的百分比;
估值器:根據當前屬性的百分比來計算改變後的屬性值。
7.3.3 屬性動畫監聽器
AnimatorListener監聽動畫的開始、結束、取消、重覆播放;
AnimatorUpdateListener 監聽整個動畫過程。
7.3.4 對任意屬性做動畫
對object的屬性abc做動畫,如果想讓動畫生效需要滿足一下兩個條件:
(1)object必須要提供setAbc方法,如果動畫的時候沒有傳遞初始值,那麼還得提供getAbc方法,否則程式直接crash;
(2)object的setAbc對屬性abc所做的改變必須能夠通過某種方法反映出來,比如帶來UI的改變。
如何給一個原始對象添加動畫可參見p285頁的方法2;
7.3.5 屬性動畫的工作原理
屬性動畫要求動畫作用的對象提供該屬性的set方法,屬性動畫根據你傳遞的該屬性的初始值和最終值,以及動畫的效果多次去掉用set方法。每次 傳遞給set方法的值都是不一樣的,確切來說是隨著時間的推移,所傳遞的值越來越接近最終值。如果動畫的時候沒有傳遞初始值,那麼還要提供get方法,因 為系統要去獲取屬性的初始值。
7.4 使用動畫的註意事項
註 意View動畫是對View的影像做動畫,並不是真正改變View的狀態,因此有時候會出現動畫完成後View無法隱藏的現象,即 setVisibility(View.GONE)失效了,這個時候只要調用view.clearAnimation()清除View動畫即可解決此問 題。
將View移動(平移)後,在Android3.0以前的系統上,不管是View動畫還是屬性動畫,新位置均無法觸發單擊事件,同時,老位置仍 然可以觸發單擊事件。儘管View已經在視覺上不存在了,將View移回原位置以後,原位置的單擊事件繼續生效。從3.0開始,屬性動畫的單擊事件觸發位 置為移動後的位置,但是View動畫仍然在原位置。