從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,以上幾個都是實現了這個接口
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
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的時候觸發.