轉載請註明出處:http://blog.csdn.net/ZhouLi_CSDN/article/details/45968639
概述
andorid系統提供了兩種動畫系統,屬性動畫和視圖動畫。屬性動畫更靈活並且功能也更強。此外,android還提供了幀動畫(drawable animation).
- 屬性動畫:andorid3.0引入,允許繪製任何對象,包括沒有顯示在屏幕上的,並且系統允許自定義類型。屬性動畫改變對象的一個field值實現動畫。指定你想要的屬性,多長時間,動畫的值就可以實現了。
- 只能使用在views上面
- 幀動畫,連續播放圖形資源
2D和3D圖形
- canvas和drawables
android系統提供了一些用戶控件,你可以擴展這些類更改它們的樣子和行爲. - open gl
系統提供了框架api和native api,使用它們可以做一些canvas不支持的api。
屬性動畫
屬性動畫特點
- Duration:可以指定時間長度,默認爲300ms。
- Time interpolation:屬性的計算方式,如先快後慢
- Repeat count and behavior:重複次數與方式,如1次,3次或者循環或者播完在反向回放。
- Repeat count and behavior:指定多個動畫。可以一起播放或者順序播放或者指定的延遲時間。
- Frame refresh delay:多長時間刷新一次,默認爲10ms,最終刷新時間受系統負載程度和硬件性能的影響。
屬性動畫如何工作
- 首先一個線性插值例子:
下圖描述了一個X屬性變化的動畫。duration :40ms,距離爲40px,每10ms,刷新一次,移動10px,在40ms的時候停止,對象停止在40px的地方。
- 非線性插值例子:
這個對象仍然在40ms內移動40px,但是在前半程加速,後半程減速。
- 相關的類:
ValueAnimation跟蹤動畫,例如動畫開始多久了和動畫屬性當前的值。
ValueAnimation封裝了一個TimeInterpolator定義時間插值,TypeEvaluator怎麼計算屬性的值。例如:例子2中TimeInterpolator使用AccelerateDecelerateInterpolator ,TypeEvaluator使用IntEvaluator.
要開始一個動畫,需要創建一個ValueAnimator,給定屬性的開始和結束值,和動畫時間長度,並調用 start()方法開始。在動畫期間,計算一個動畫以進行時間的百分比(0-1)。
TypeEvaluator:根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值。
ValueAnimation計算運行時間後,調用當前設定的TimeInterpolator ,計算出一個interpolated fraction,最後TypeAnimator通過這個因子計算出屬性值,如上例中10ms時:
經插值計算(inteplator)後的插值因子:大約爲0.15,上述例子中用了AccelerateDecelerateInterpolator,計算公式爲(input即爲時間因子):
(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
最後根據TypeEvaluator計算出在10ms時的屬性值:0.15*(40-0)=6pixel。上例中TypeEvaluator爲FloatEvaluator,計算方法爲 :
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
屬性動畫與視圖動畫區別
- 視圖動畫只允許對views對象設置動畫,例如對view做放大和旋轉,但是不能對view的背景顏色做改變 。
- 視圖動畫的另一個缺點是它只是改變了view在什麼地方draw ,並不是實際的view。例如,當你把一個button移動到另一個地方,但是button可以相應點擊事件的位置並沒有改變。
- 屬性動畫沒有這些問題,你可以改變任何對象,的屬性,例如顏色,位置,大小。
應用屬性動畫有兩個步驟:
- 計算屬性值
根據屬性值執行相應的動作,如改變對象的某一屬性。
- ValueAnimation:只進行了第一步;需要實現ValueAnimator.onUpdateListener接口設置屬性。
- ObjectAnimation:兩步都做,但是需要設置屬性的get和set方法。
- 根據應用動畫的對象或屬性的不同,可能需要在onAnimationUpdate函數中調用invalidate()函數刷新視圖。
AnimationSet:動畫集合。
計算器(Evaluators):根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值。
- IntEvaluator:整型屬性
- FloatEvalluator:浮點型
- ArgbEvaluator:顏色屬性
- TypeEvaluator:自定義計算方法
- 插值器:( TimeInterpolator)
- AccelerateInterpolator 加速插值器
- AccelerateDecelerateInterpolator 加速減速插值器
- LinearInterpolator 線性插值器
- BounceInterpolator 彈跳插值器
- AnticipateInterpolator 回盪鞦韆插值器
- AnticipateOvershootInterpolator
- CycleInterpolator 正弦週期變化插值器
- OvershootInterpolator
關於插值器可以參考這篇文章:插值器詳細介紹
ValueAnimator:
通過ValueAnimator的ofInt(),ofFloat,ofObeact()方法獲得,
需要實現監聽器更改要改變的對象的屬性值。
ObjectAnimator
初始化需要指定對象和對象的屬性以及值區間。
有些改變需要調用invalidate()方法,重繪。可以在onAnimationUpdate()方法中做。
AnimatorSet
包含動畫的集合,也可以自嵌套,例如:
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
Animation Listeners
- Animator.AnimatorListener:
- ValueAnimator.AnimatorUpdateListener:
- AnimatorListenerAdapter:
爲viewGroup的layout改變設置動畫
ViewGroup中的子元素可以通過setVisibility使其Visible、Invisible或Gone,當有子元素可見性改變時(VISIBLE、GONE),可以向其應用動畫,通過LayoutTransition類應用此類動畫:
通過setAnimator應用動畫,第一個參數表示應用的情境,可以以下4種類型:
- APPEARING: 當一個元素在其父元素中變爲Visible時對這個元素應用動畫
- CHANGE_APPEARING: 當一個元素在其父元素中變爲Visible時,因系統要重新佈局有一些元素需要移動,對這些要移動的元素應用動畫
- DISAPPEARING: 當一個元素在其父元素中變爲GONE時對其應用動畫
- CHANGE_DISAPPEARING: 當一個元素在其父元素中變爲GONE時,因系統要重新佈局有一些元素需要移動,這些要移動的元素應用動畫.
可以使用自定義動畫也可以使用默認的;默認可以在xml設置:
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />
使用TypeEvalutor
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
KeyFrams:
keyFrame是一個 時間/值 對,通過它可以定義一個在特定時間的特定狀態,即關鍵幀,而且在兩個keyFrame之間可以定義不同的Interpolator,就好像多個動畫的拼接,第一個動畫的結束點是第二個動畫的開始點。KeyFrame是抽象類,要通過ofInt(),ofFloat(),ofObject()獲得適當的KeyFrame,然後通過PropertyValuesHolder.ofKeyframe獲得PropertyValuesHolder對象,如以下例子:
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
Animation Views:
在View Animation中,對View應用Animation並沒有改變View的屬性,動畫的實現是通過其Parent View實現的,在View被drawn時Parents View改變它的繪製參數,draw後再改變參數invalidate,這樣雖然View的大小或旋轉角度等改變了,但View的實際屬性沒變,所以有效區域還是應用動畫之前的區域,比如你把一按鈕放大兩倍,但還是放大這前的區域可以觸發點擊事件。爲了改變這一點,在Android 3.0中給View增加了一些參數並對這些參數增加了相應的getter/setter函數(ObjectAnimator要用這些函數改變這些屬性):
translationX,translationY: View相對於原始位置的偏移量
rotation,rotationX,rotationY: 旋轉,rotation用於2D旋轉角度,3D中用到後兩個
scaleX,scaleY: 縮放比
x,y: View的最終座標,是View的left,top位置加上translationX,translationY
alpha: 透明度
跟位置有關的參數有3個,以X座標爲例,可以通過getLeft(),getX(),getTranslateX()獲得,若有一Button btn2,佈局時其座標爲(40,0):
//應用動畫之前
btn2.getLeft(); //40
btn2.getX(); //40
btn2.getTranslationX(); //0
//應用translationX動畫
ObjectAnimator oa=ObjectAnimator.ofFloat(btn2,"translationX", 200);
oa.setDuration(2000);
oa.start();
/*應用translationX動畫後
btn2.getLeft(); //40
btn2.getX(); //240
btn2.getTranslationX(); //200
*/
//應用X動畫,假設沒有應用之前的translationX動畫
ObjectAnimator oa=ObjectAnimator.ofFloat(btn2, "x", 200);
oa.setDuration(2000);
oa.start();
/*應用X動畫後
btn2.getLeft(); //40
btn2.getX(); //200
btn2.getTranslationX(); //160
*/
無論怎樣應用動畫,原來的佈局時的位置通過getLeft()獲得,保持不變;
X是View最終的位置;
translationX爲最終位置與佈局時初始位置這差。
所以若就用translationX即爲在原來基礎上移動多少,X爲最終多少
getX()的值爲getLeft()與getTranslationX()的和
對於X動畫,源代碼是這樣的:
case X:
info.mTranslationX = value - mView.mLeft;
break;
Property Animation也可以在XML中定義
- - AnimatorSet
- - ValueAnimator
- - ObjectAnimator
XML文件應放大/res/animator/中,通過以下方式應用動畫:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator);
set.setTarget(myObject);
set.start();
ViewPropertyAnimator:
如果需要對一個View的多個屬性進行動畫可以用ViewPropertyAnimator類,該類對多屬性動畫進行了優化,會合並一些invalidate()來減少刷新視圖,該類在3.1中引入。
以下三段代碼實現同樣的效果:
- Multiple ObjectAnimator objects
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
- One ObjectAnimator
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
- ViewPropertyAnimator
myView.animate().x(50f).y(100f);
在XMl中聲明animation
在3.1以後,聲明屬性動畫必須在res/animator/路徑下。例如:
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
運行:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();