android動畫之屬性動畫學習

    從api11開始,也就是Android3.0開始, google爲android平臺引入了一個新的動畫框架,即屬性動畫property animation, 3.0以前的系統要使用property animation需要引入nineoldandroid工程,我們的程序中要對不同的sdk版本做判斷.可以說,屬性動畫是android系統中所有動畫框架中最重要的一個,與我們平常用到的 view animator相比,view animation只能針對view及其子類中的alpha屬性,transation屬性,sale屬性,這極大的限制了我們的需求,而property animation適用於任何對象的任何屬性,這是屬性動畫最具優勢的地方.

   1.先簡單分析一下View Animation的用法和其特點.

      View Animation(Tween Animation):補間動畫,給出兩個關鍵幀,通過一些算法將給定屬性值在給定的時間內在兩個關鍵幀間漸變。View animation只能應用於View對象,而且只支持一部分屬性,如支持縮放旋轉而不支持背景顏色的改變。而且對於View animation,它只是改變了View對象繪製的位置,而沒有改變View對象本身,比如,你有一個Button,座標(100,100),Width:200,Height:50,而你有一個動畫使其變爲Width:100,Height:100,你會發現動畫過程中觸發按鈕點擊的區域仍是(100,100)-(300,150)。

View Animation就是一系列View形狀的變換,如大小的縮放,透明度的改變,位置的改變,動畫的定義既可以用代碼定義也可以用XML定義,當然,建議用XML定義。

可以給一個View同時設置多個動畫,比如從透明至不透明的淡入效果,與從小到大的放大效果,這些動畫可以同時進行,也可以在一個完成之後開始另一個。

用XML定義的動畫放在/res/anim/文件夾內,XML文件的根元素可以爲<alpha>,<scale>,<translate>,<rotate>,interpolator元素或<set>(表示以上幾個動畫的集合,set可以嵌套)。

     示例代碼:

<span style="font-size:18px;">   ImageView spaceshipImage = (ImageView)findViewById(R.id.spaceshipImage); 
   Animation hyperspaceJumpAnimation=AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump); 
   spaceshipImage.startAnimation(hyperspaceJumpAnimation);</span>
   2.Drawable Animation(Frame Animation)用法

      Drawable Animation(Frame Animation):幀動畫,就像GIF圖片,通過一系列Drawable依次顯示來模擬動畫的效果。在XML中的定義方式如下:

<span style="font-size:18px;">   <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
     android:oneshot="true">
      <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
      <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
      <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
   </animation-list></span>
  3.本文要重點介紹的屬性動畫的用法和要注意的地方

     首先看屬性動畫框架在android源碼中的位置,如下圖所示:

     整個框架中最重要的幾個類是:Animator,KeyFrame,LayoutTransation,ObjectAnimator,ValueAnimator,TypeEvaluator

         1)ValueAnimator包含Property Animation動畫的所有核心功能,如動畫時間,開始、結束屬性值,相應時間屬性值計算方法等。應用Property Animation有兩個步聚:

            1.計算屬性值 2.根據屬性值執行相應的動作,如改變對象的某一屬性。ValuAnimiator只完成了第一步工作,如果要完成第二步,需要實現ValueAnimator.onUpdateListener接口,這個接口只有一個函數onAnimationUpdate(),在這個函數中會傳入ValueAnimator對象做爲參數,通過這個ValueAnimator對象的getAnimatedValue()函數可以得到當前的屬性值如: 

<span style="font-size:18px;">ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.addUpdateListener(new AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Log.i("update", ((Float) animation.getAnimatedValue()).toString());
    }
});
animation.setInterpolator(new CycleInterpolator(3));
animation.start();</span>

   2)ObjectAnimation繼承自ValueAnimator,要指定一個對象及該對象的一個屬性,當屬性值計算完成時自動設置爲該對象的相應屬性,即完成了Property Animation的全部兩步操作。實際應用中一般都會用ObjectAnimator來改變某一對象的某一屬性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,應該滿足以下條件:

  • 對象應該有一個setter函數:set<PropertyName>(駝峯命名法)
  • 如上面的例子中,像ofFloat之類的工場方法,第一個參數爲對象名,第二個爲屬性名,後面的參數爲可變參數,如果values…參數只設置了一個值的話,那麼會假定爲目的值,屬性值的變化範圍爲當前值到目的值,爲了獲得當前值,該對象要有相應屬性的getter方法:get<PropertyName>
  • 如果有getter方法,其應返回值類型應與相應的setter方法的參數類型一致。

如果上述條件不滿足,則不能用ObjectAnimator,應用ValueAnimator代替。

<span style="font-size:18px;">tv=(TextView)findViewById(R.id.textview1);
btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
    ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
    oa.setDuration(3000);
    oa.start();
  }
});</span>
根據應用動畫的對象或屬性的不同,可能需要在onAnimationUpdate函數中調用invalidate()函數刷新視圖。

    3)根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值,android提供了以下幾個evalutor:

  • IntEvaluator:屬性的值類型爲int;
  • FloatEvaluator:屬性的值類型爲float;
  • ArgbEvaluator:屬性的值類型爲十六進制顏色值;
  • TypeEvaluator:一個接口,可以通過實現該接口自定義Evaluator。

自定義TypeEvalutor很簡單,只需要實現一個方法,如FloatEvalutor的定義:

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);
    }
}

根據動畫執行的時間跟應用的Interplator,會計算出一個0~1之間的因子,即evalute函數中的fraction參數,通過上述FloatEvaluator應該很好看出其意思。Time interplator定義了屬性值變化的方式,如線性均勻改變,開始慢然後逐漸快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,這兩個是一樣的,在3.0之前只有Interplator,3.0之後實現代碼轉移至了TimeInterplator。Interplator繼承自TimeInterplator,內部沒有任何其他代碼。

  • AccelerateInterpolator          加速,開始時慢中間加速
  • DecelerateInterpolator         減速,開始時快然後減速
  • AccelerateDecelerateInterolator    先加速後減速,開始結束時慢,中間加速
  • AnticipateInterpolator        反向 ,先向相反方向改變一段再加速播放
  • AnticipateOvershootInterpolator    反向加回彈,先向相反方向改變,再加速播放,會超出目的值然後緩慢移動至目的值
  • BounceInterpolator         跳躍,快到目的值時值會跳躍,如目的值100,後面的值可能依次爲85,77,70,80,90,100
  • CycleIinterpolator         循環,動畫循環一定次數,值的改變爲一正弦函數:Math.sin(2 * mCycles * Math.PI * input)
  • LinearInterpolator         線性,線性均勻改變
  • OvershottInterpolator        回彈,最後超出目的值然後緩慢改變到目的值
  • TimeInterpolator           一個接口,允許你自定義interpolator,以上幾個都是實現了這個接口
     5)LayoutTransation用法, ViewGroup中的子元素可以通過setVisibility使其Visible、Invisible或Gone,當有子元素可見性改變時(VISIBLE、GONE),可以向其應用動畫,通過LayoutTransition類應用此類動畫:
transition.setAnimator(LayoutTransition.DISAPPEARING, customDisappearingAnim);

通過setAnimator應用動畫,第一個參數表示應用的情境,可以以下4種類型:

  • APPEARING        當一個元素在其父元素中變爲Visible時對這個元素應用動畫
  • CHANGE_APPEARING    當一個元素在其父元素中變爲Visible時,因系統要重新佈局有一些元素需要移動,對這些要移動的元素應用動畫
  • DISAPPEARING       當一個元素在其父元素中變爲GONE時對其應用動畫
  • CHANGE_DISAPPEARING   當一個元素在其父元素中變爲GONE時,因系統要重新佈局有一些元素需要移動,這些要移動的元素應用動畫.

第二個參數爲一Animator。

mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);

此函數設置動畫延遲時間,參數分別爲類型與時間。通常我們都是採用系統默認提供的動畫.

      6)keyFrame是一個 時間/值 對,通過它可以定義一個在特定時間的特定狀態,即關鍵幀,而且在兩個keyFrame之間可以定義不同的Interpolator,就好像多個動畫的拼接,第一個動畫的結束點是第二個動畫的開始點。KeyFrame是抽象類,要通過ofInt(),ofFloat(),ofObject()獲得適當的KeyFrame,然後通過PropertyValuesHolder.ofKeyframe獲得PropertyValuesHolder對象,如以下例子:

Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn2, pvhRotation);
rotationAnim.setDuration(2000);

上述代碼的意思爲:設置btn對象的width屬性值使其:

  • 開始時 Width=400
  • 動畫開始1/4時 Width=200
  • 動畫開始1/2時 Width=400
  • 動畫開始3/4時 Width=100
  • 動畫結束時 Width=500
第一個參數爲時間百分比,第二個參數是在第一個參數的時間時的屬性值。
定義了一些Keyframe後,通過PropertyValuesHolder類的方法ofKeyframe一個PropertyValuesHolder對象,然後通過ObjectAnimator.ofPropertyValuesHolder獲得一個Animator對象。
用下面的代碼可以實現同樣的效果(上述代碼時間值是線性,變化均勻):
ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500);
oa.setDuration(2000);
oa.start();
      

   以下是 對View Animation動畫的補充:

    在View Animation動畫框架中,我們未說到LayoutAnimationControll這個類的作用,見名知意,其是用來控制ViewGroup的動畫的,具體作用就是讓對應的ViewGroup中的所有子View都有相同的動畫,並在佈局生成的過程中產生動畫效果,例如,通過這個類,我們可以實現,ListView中所有的條目依次出現的效果.那他與LayoutTransation有何區別呢,區別就是此動畫是在ViewGroup繪製時產生效果,而LayoutTransation則是在VierwGroup中add或remove View的時候觸發.





    



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章