屬性動畫(Property Animation)

轉載請註明出處:http://blog.csdn.net/ZhouLi_CSDN/article/details/45968639

概述

andorid系統提供了兩種動畫系統,屬性動畫和視圖動畫。屬性動畫更靈活並且功能也更強。此外,android還提供了幀動畫(drawable animation).

  1. 屬性動畫:andorid3.0引入,允許繪製任何對象,包括沒有顯示在屏幕上的,並且系統允許自定義類型。屬性動畫改變對象的一個field值實現動畫。指定你想要的屬性,多長時間,動畫的值就可以實現了。
  2. 只能使用在views上面
  3. 幀動畫,連續播放圖形資源

2D和3D圖形

  1. canvas和drawables
    android系統提供了一些用戶控件,你可以擴展這些類更改它們的樣子和行爲.
  2. 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,最終刷新時間受系統負載程度和硬件性能的影響。

屬性動畫如何工作

  1. 首先一個線性插值例子:
    下圖描述了一個X屬性變化的動畫。duration :40ms,距離爲40px,每10ms,刷新一次,移動10px,在40ms的時候停止,對象停止在40px的地方。
    這裏寫圖片描述
  2. 非線性插值例子:
    這個對象仍然在40ms內移動40px,但是在前半程加速,後半程減速。
    這裏寫圖片描述
  3. 相關的類:
    這裏寫圖片描述
    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);
}

屬性動畫與視圖動畫區別

  1. 視圖動畫只允許對views對象設置動畫,例如對view做放大和旋轉,但是不能對view的背景顏色做改變 。
  2. 視圖動畫的另一個缺點是它只是改變了view在什麼地方draw ,並不是實際的view。例如,當你把一個button移動到另一個地方,但是button可以相應點擊事件的位置並沒有改變。
  3. 屬性動畫沒有這些問題,你可以改變任何對象,的屬性,例如顏色,位置,大小。

應用屬性動畫有兩個步驟:

  1. 計算屬性值
  2. 根據屬性值執行相應的動作,如改變對象的某一屬性。

    1. ValueAnimation:只進行了第一步;需要實現ValueAnimator.onUpdateListener接口設置屬性。
    2. ObjectAnimation:兩步都做,但是需要設置屬性的get和set方法。
    3. 根據應用動畫的對象或屬性的不同,可能需要在onAnimationUpdate函數中調用invalidate()函數刷新視圖。
      AnimationSet:動畫集合。
  3. 計算器(Evaluators):根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值。

    1. IntEvaluator:整型屬性
    2. FloatEvalluator:浮點型
    3. ArgbEvaluator:顏色屬性
    4. TypeEvaluator:自定義計算方法
  4. 插值器:( TimeInterpolator)
    1. AccelerateInterpolator 加速插值器
    2. AccelerateDecelerateInterpolator 加速減速插值器
    3. LinearInterpolator 線性插值器
    4. BounceInterpolator 彈跳插值器
    5. AnticipateInterpolator 回盪鞦韆插值器
    6. AnticipateOvershootInterpolator
    7. CycleInterpolator 正弦週期變化插值器
    8. 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();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章