3.0之前,android支持兩種動畫模式,tween animation,frame animation,在android3.0中又引入了一個新的動畫系統:property animation,這三種動畫模式在SDK中被稱爲property animation,view animation,drawable animation。 android
View Animation(Tween Animation):補間動畫,給出兩個關鍵幀,經過一些算法將給定屬性值在給定的時間內在兩個關鍵幀間漸變。算法
View animation只能應用於View對象,並且只支持一部分屬性,如支持縮放旋轉而不支持背景顏色的改變。app
並且對於View animation,它只是改變了View對象繪製的位置,而沒有改變View對象自己,好比,你有一個Button,座標(100,100),Width:200,Height:50,而你有一個動畫使其變爲Width:100,Height:100,你會發現動畫過程當中觸發按鈕點擊的區域還是(100,100)-(300,150)。ide
View Animation就是一系列View形狀的變換,如大小的縮放,透明度的改變,位置的改變,動畫的定義既能夠用代碼定義也能夠用XML定義,固然,建議用XML定義。函數
能夠給一個View同時設置多個動畫,好比從透明至不透明的淡入效果,與從小到大的放大效果,這些動畫能夠同時進行,也能夠在一個完成以後開始另外一個。佈局
用XML定義的動畫放在/res/anim/文件夾內,XML文件的根元素能夠爲<alpha>,<scale>,<translate>,<rotate>,interpolator元素或<set>(表示以上幾個動畫的集合,set能夠嵌套)。默認狀況下,全部動畫是同時進行的,能夠經過startOffset屬性設置各個動畫的開始偏移(開始時間)來達到動畫順序播放的效果。優化
能夠經過設置interpolator屬性改變更畫漸變的方式,如AccelerateInterpolator,開始時慢,而後逐漸加快。默認爲AccelerateDecelerateInterpolator。動畫
定義好動畫的XML文件後,能夠經過相似下面的代碼對指定View應用動畫。this
ImageView spaceshipImage = (ImageView)findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation=AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
Drawable Animation(Frame Animation):幀動畫,就像GIF圖片,經過一系列Drawable依次顯示來模擬動畫的效果。在XML中的定義方式以下:lua
1 |
< animation-list xmlns:android = "http://schemas.android.com/apk/res/android" |
2 |
android:oneshot = "true" > |
3 |
< item android:drawable = "@drawable/rocket_thrust1" android:duration = "200" /> |
4 |
5 |
< item android:drawable = "@drawable/rocket_thrust2" android:duration = "200" /> |
6 |
< item android:drawable = "@drawable/rocket_thrust3" android:duration = "200" /> |
7 |
</ animation-list > |
必須以<animation-list>爲根元素,以<item>表示要輪換顯示的圖片,duration屬性表示各項顯示的時間。XML文件要放在/res/drawable/目錄下。示例:
protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); imageView = (ImageView) findViewById(R.id.imageView1); imageView.setBackgroundResource(R.drawable.drawable_anim); anim = (AnimationDrawable) imageView.getBackground(); } public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { anim.stop(); anim.start(); return true; } return super.onTouchEvent(event); }
我在實驗中遇到兩點問題:
屬性動畫,這個是在Android 3.0中才引進的,之前學WPF時裏面的動畫機制好像就是這個,它更改的是對象的實際屬性,在View Animation(Tween Animation)中,其改變的是View的繪製效果,真正的View的屬性保持不變,好比不管你在對話中如何縮放Button的大小,Button的有效點擊區域仍是沒有應用動畫時的區域,其位置與大小都不變。而在Property Animation中,改變的是對象的實際屬性,如Button的縮放,Button的位置與大小屬性值都改變了。並且Property Animation不止能夠應用於View,還能夠應用於任何對象。Property Animation只是表示一個值在一段時間內的改變,當值改變時要作什麼事情徹底是你本身決定的。
在Property Animation中,能夠對動畫應用如下屬性:
對於下圖的動畫,這個對象的X座標在40ms內從0移動到40 pixel.按默認的10ms刷新一次,這個對象會移動4次,每次移動40/4=10pixel。
也能夠改變屬性值的改變方法,即設置不一樣的interpolation,在下圖中運動速度先逐漸增大再逐漸減少
下圖顯示了與上述動畫相關的關鍵對象
ValueAnimator即表示一個動畫,包含動畫的開始值,結束值,持續時間等屬性。
ValueAnimator封裝了一個TimeInterpolator,TimeInterpolator定義了屬性值在開始值與結束值之間的插值方法。
ValueAnimator還封裝了一個TypeAnimator,根據開始、結束值與TimeIniterpolator計算獲得的值計算出屬性值。
ValueAnimator根據動畫已進行的時間跟動畫總時間(duration)的比計算出一個時間因子(0~1),而後根據TimeInterpolator計算出另外一個因子,最後TypeAnimator經過這個因子計算出屬性值,如上例中10ms時:
首先計算出時間因子,即通過的時間百分比:t=10ms/40ms=0.25
經插值計算(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); }
參數分別爲上一步的插值因子,開始值與結束值。
ValueAnimator包含Property Animation動畫的全部核心功能,如動畫時間,開始、結束屬性值,相應時間屬性值計算方法等。應用Property Animation有兩個步聚:
ValuAnimiator只完成了第一步工做,若是要完成第二步,須要實現ValueAnimator.onUpdateListener接口,如:
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();
此示例中只是向Logcat輸出了一些信息,能夠改成想作的工做。
Animator.AnimatorListener
onAnimationStart() onAnimationEnd() onAnimationRepeat() onAnimationCancel
ValueAnimator.AnimatorUpdateListener
onAnimationUpdate() //經過監聽這個事件在屬性的值更新時執行相應的操做,對於ValueAnimator通常要監聽此事件執行相應的動做,否則Animation沒意義(可用於計時),在ObjectAnimator(繼承自ValueAnimator)中會自動更新屬性,如無必要沒必要監聽。在函數中會傳遞一個ValueAnimator參數,經過此參數的getAnimatedValue()取得當前動畫屬性值。
能夠繼承AnimatorListenerAdapter而不是實現AnimatorListener接口來簡化操做,這個類對AnimatorListener中的函數都定義了一個空函數體,這樣咱們就只用定義想監聽的事件而不用實現每一個函數卻只定義一空函數體。
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f); oa.setDuration(3000); oa.addListener(new AnimatorListenerAdapter(){ public void on AnimationEnd(Animator animation){ Log.i("Animation","end"); } }); oa.start();
繼承自ValueAnimator,要指定一個對象及該對象的一個屬性,當屬性值計算完成時自動設置爲該對象的相應屬性,即完成了Property Animation的所有兩步操做。實際應用中通常都會用ObjectAnimator來改變某一對象的某一屬性,但用ObjectAnimator有必定的限制,要想使用ObjectAnimator,應該知足如下條件:
若是上述條件不知足,則不能用ObjectAnimator,應用ValueAnimator代替。
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(); } });
把一個TextView的透明度在3秒內從0變至1。
根據應用動畫的對象或屬性的不一樣,可能須要在onAnimationUpdate函數中調用invalidate()函數刷新視圖。
AnimationSet提供了一個把多個動畫組合成一個組合的機制,並可設置組中動畫的時序關係,如同時播放,順序播放等。
如下例子同時應用5個動畫:
1 |
AnimatorSet bouncer = new AnimatorSet(); |
2 |
bouncer.play(anim1).before(anim2); |
3 |
bouncer.play(anim2).with(anim3); |
4 |
bouncer.play(anim2).with(anim4) |
5 |
bouncer.play(anim5).after(amin2); |
6 |
animatorSet.start(); |
根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值,android提供瞭如下幾個evalutor:
自定義TypeEvalutor很簡單,只須要實現一個方法,如FloatEvalutor的定義:
1 |
public class FloatEvaluator implements TypeEvaluator { |
2 |
public Object evaluate( float fraction, Object startValue, Object endValue) { |
3 |
float startFloat = ((Number) startValue).floatValue(); |
4 |
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat); |
5 |
} |
6 |
} |
根據動畫執行的時間跟應用的Interplator,會計算出一個0~1之間的因子,即evalute函數中的fraction參數,經過上述FloatEvaluator應該很好看出其意思。
time interplator定義了屬性值變化的方式,如線性均勻改變,開始慢而後逐漸快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,這兩個是同樣的,在3.0以前只有Interplator,3.0以後實現代碼轉移至了TimeInterplator。Interplator繼承自TimeInterplator,內部沒有任何其餘代碼。
ViewGroup中的子元素能夠經過setVisibility使其Visible、Invisible或Gone,當有子元素可見性改變時,能夠向其應用動畫,經過LayoutTransition類應用此類動畫:
transition.setAnimator(LayoutTransition.DISAPPEARING, customDisappearingAnim);
經過setAnimator應用動畫,第一個參數表示應用的情境,能夠如下4種類型:
第二個參數爲一Animator。
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
此函數設置動畫持續時間,參數分別爲類型與時間。
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屬性值使其:
ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500); oa.setDuration(2000); oa.start();
在View Animation中,對View應用Animation並無改變View的屬性,動畫的實現是經過其Parent View實現的,在View被drawn時Parents View改變它的繪製參數,draw後再改變參數invalidate,這樣雖然View的大小或旋轉角度等改變了,但View的實際屬性沒變,因此有效區域仍是應用動畫以前的區域,好比你把一按鈕放大兩倍,但仍是放大這前的區域能夠觸發點擊事件。爲了改變這一點,在Android 3.0中給View增長了一些參數並對這些參數增長了相應的getter/setter函數(ObjectAnimator要用這些函數改變這些屬性):
//應用動畫以前btn2.getLeft(); //40btn2.getX(); //40btn2.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*/
case X: info.mTranslationX = value - mView.mLeft; break;
Property Animation也能夠在XML中定義
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator); set.setTarget(myObject); set.start();
若是須要對一個View的多個屬性進行動畫能夠用ViewPropertyAnimator類,該類對多屬性動畫進行了優化,會合並一些invalidate()來減小刷新視圖,該類在3.1中引入。
如下兩段代碼實現一樣的效果:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f); ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
myView.animate().x(50f).y(100f);