3.0以前脆侮,android支持兩種動畫模式,tween animation,frame animation勇劣,在android3.0中又引入了一個新的動畫系統(tǒng):property animation靖避,這三種動畫模式在SDK中被稱為property animation,view animation,drawable animation。 可通過NineOldAndroids項目在3.0之前的系統(tǒng)中使用Property Animation
1. View Animation(Tween Animation)
View Animation(Tween Animation):補(bǔ)間動畫比默,給出兩個關(guān)鍵幀幻捏,通過一些算法將給定屬性值在給定的時間內(nèi)在兩個關(guān)鍵幀間漸變。
View animation只能應(yīng)用于View對象命咐,而且只支持一部分屬性篡九,如支持縮放旋轉(zhuǎn)而不支持背景顏色的改變。
而且對于View animation醋奠,它只是改變了View對象繪制的位置榛臼,而沒有改變View對象本身,比如窜司,你有一個Button沛善,坐標(biāo)(100,100),Width:200,Height:50例证,而你有一個動畫使其變?yōu)閃idth:100,Height:100迷捧,你會發(fā)現(xiàn)動畫過程中觸發(fā)按鈕點擊的區(qū)域仍是(100,100)-(300,150)织咧。
View Animation就是一系列View形狀的變換,如大小的縮放漠秋,透明度的改變笙蒙,位置的改變,動畫的定義既可以用代碼定義也可以用XML定義庆锦,當(dāng)然捅位,建議用XML定義。
可以給一個View同時設(shè)置多個動畫,比如從透明至不透明的淡入效果艇搀,與從小到大的放大效果尿扯,這些動畫可以同時進(jìn)行,也可以在一個完成之后開始另一個焰雕。
用XML定義的動畫放在/res/anim/文件夾內(nèi)衷笋,XML文件的根元素可以為,,,,interpolator元素或(表示以上幾個動畫的集合,set可以嵌套)矩屁。默認(rèn)情況下辟宗,所有動畫是同時進(jìn)行的,可以通過startOffset屬性設(shè)置各個動畫的開始偏移(開始時間)來達(dá)到動畫順序播放的效果泊脐。
可以通過設(shè)置interpolator屬性改變動畫漸變的方式容客,如AccelerateInterpolator耘柱,開始時慢,然后逐漸加快。默認(rèn)為AccelerateDecelerateInterpolator娄柳。
定義好動畫的XML文件后赤拒,可以通過類似下面的代碼對指定View應(yīng)用動畫。
ImageView spaceshipImage = (ImageView)findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation=AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
2. Drawable Animation(Frame Animation)
Drawable Animation(Frame Animation):幀動畫,就像GIF圖片始衅,通過一系列Drawable依次顯示來模擬動畫的效果蝙茶。在XML中的定義方式如下:
必須以為根元素,以表示要輪換顯示的圖片吮廉,duration屬性表示各項顯示的時間。XML文件要放在/res/drawable/目錄下。示例:
protectedvoidonCreate(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();
}
publicbooleanonTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
anim.stop();
anim.start();
returntrue;
}
returnsuper.onTouchEvent(event);
}
我在實驗中遇到兩點問題:
要在代碼中調(diào)用Imageview的setBackgroundResource方法,如果直接在XML布局文件中設(shè)置其src屬性當(dāng)觸發(fā)動畫時會FC。
在動畫start()之前要先stop(),不然在第一次動畫之后會停在最后一幀劳跃,這樣動畫就只會觸發(fā)一次。
最后一點是SDK中提到的杉武,不要在onCreate中調(diào)用start倘要,因為AnimationDrawable還沒有完全跟Window相關(guān)聯(lián)志鹃,如果想要界面顯示時就開始動畫的話曹铃,可以在onWindowFoucsChanged()中調(diào)用start()秘血。
3. Property Animation
屬性動畫,這個是在Android 3.0中才引進(jìn)的,以前學(xué)WPF時里面的動畫機(jī)制好像就是這個,它更改的是對象的實際屬性晰骑,在View Animation(Tween Animation)中,其改變的是View的繪制效果,真正的View的屬性保持不變,比如無論你在對話中如何縮放Button的大小刊咳,Button的有效點擊區(qū)域還是沒有應(yīng)用動畫時的區(qū)域,其位置與大小都不變酵镜。而在Property Animation中,改變的是對象的實際屬性,如Button的縮放,Button的位置與大小屬性值都改變了。而且Property Animation不止可以應(yīng)用于View啸澡,還可以應(yīng)用于任何對象上沐。Property Animation只是表示一個值在一段時間內(nèi)的改變龄广,當(dāng)值改變時要做什么事情完全是你自己決定的净宵。
在Property Animation中,可以對動畫應(yīng)用以下屬性:
Duration:動畫的持續(xù)時間
TimeInterpolation:屬性值的計算方式,如先快后慢
TypeEvaluator:根據(jù)屬性的開始番舆、結(jié)束值與TimeInterpolation計算出的因子計算出當(dāng)前時間的屬性值
Repeat Count and behavoir:重復(fù)次數(shù)與方式呛讲,如播放3次、5次、無限循環(huán),可以此動畫一直重復(fù),或播放完時再反向播放
Animation sets:動畫集合,即可以同時對一個對象應(yīng)用幾個動畫,這些動畫可以同時播放也可以對不同動畫設(shè)置不同開始偏移
Frame refreash delay:多少時間刷新一次壶谒,即每隔多少時間計算一次屬性值呵俏,默認(rèn)為10ms录平,最終刷新時間還受系統(tǒng)進(jìn)程調(diào)度與硬件的影響
3.1 Property Animation的工作方式
對于下圖的動畫,這個對象的X坐標(biāo)在40ms內(nèi)從0移動到40 pixel.按默認(rèn)的10ms刷新一次彼水,這個對象會移動4次,每次移動40/4=10pixel拥峦。
也可以改變屬性值的改變方法璃哟,即設(shè)置不同的interpolation铐伴,在下圖中運(yùn)動速度先逐漸增大再逐漸減小
下圖顯示了與上述動畫相關(guān)的關(guān)鍵對象
ValueAnimator ?表示一個動畫玲献,包含動畫的開始值眠砾,結(jié)束值,持續(xù)時間等屬性托酸。
ValueAnimator封裝了一個TimeInterpolator褒颈,TimeInterpolator定義了屬性值在開始值與結(jié)束值之間的插值方法。
ValueAnimator還封裝了一個TypeAnimator获高,根據(jù)開始、結(jié)束值與TimeIniterpolator計算得到的值計算出屬性值吻育。
ValueAnimator根據(jù)動畫已進(jìn)行的時間跟動畫總時間(duration)的比計算出一個時間因子(0~1)念秧,然后根據(jù)TimeInterpolator計算出另一個因子,最后TypeAnimator通過這個因子計算出屬性值布疼,如上例中10ms時:
首先計算出時間因子摊趾,即經(jīng)過的時間百分比:t=10ms/40ms=0.25
經(jīng)插值計算(inteplator)后的插值因子:大約為0.15,上述例子中用了AccelerateDecelerateInterpolator游两,計算公式為(input即為時間因子):
(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
最后根據(jù)TypeEvaluator計算出在10ms時的屬性值:0.15*(40-0)=6pixel砾层。上例中TypeEvaluator為FloatEvaluator,計算方法為 :
public Float evaluate(floatfraction, Number startValue, Number endValue) {floatstartFloat =startValue.floatValue();returnstartFloat + fraction * (endValue.floatValue() -startFloat);
}
參數(shù)分別為上一步的插值因子贱案,開始值與結(jié)束值肛炮。
3.2 ValueAnimator
ValueAnimator包含Property Animation動畫的所有核心功能,如動畫時間宝踪,開始侨糟、結(jié)束屬性值,相應(yīng)時間屬性值計算方法等瘩燥。應(yīng)用Property Animation有兩個步聚:
計算屬性值
根據(jù)屬性值執(zhí)行相應(yīng)的動作秕重,如改變對象的某一屬性。
ValuAnimiator只完成了第一步工作厉膀,如果要完成第二步溶耘,需要實現(xiàn)ValueAnimator.onUpdateListener接口,這個接口只有一個函數(shù)onAnimationUpdate()服鹅,在這個函數(shù)中會傳入ValueAnimator對象做為參數(shù)凳兵,通過這個ValueAnimator對象的getAnimatedValue()函數(shù)可以得到當(dāng)前的屬性值如:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.addUpdateListener(newAnimatorUpdateListener() {
@Override
publicvoidonAnimationUpdate(ValueAnimator animation) {
Log.i("update", ((Float) animation.getAnimatedValue()).toString());
}
});
animation.setInterpolator(newCycleInterpolator(3));
animation.start();
此示例中只是向Logcat輸出了一些信息,可以改為想做的工作企软。
Animator.AnimatorListener
onAnimationStart()
onAnimationEnd()
onAnimationRepeat()//當(dāng)動畫被取消時調(diào)用留荔,同時會調(diào)用onAnimationEnd().onAnimationCancel()
ValueAnimator.AnimatorUpdateListener
onAnimationUpdate()//通過監(jiān)聽這個事件在屬性的值更新時執(zhí)行相應(yīng)的操作,對于ValueAnimator一般要監(jiān)聽此事件執(zhí)行相應(yīng)的動作,不然Animation沒意義聚蝶,在ObjectAnimator(繼承自ValueAnimator)中會自動更新屬性杰妓,如無必要不必監(jiān)聽。在函數(shù)中會傳遞一個ValueAnimator參數(shù)碘勉,通過此參數(shù)的getAnimatedValue()取得當(dāng)前動畫屬性值巷挥。
可以繼承AnimatorListenerAdapter而不是實現(xiàn)AnimatorListener接口來簡化操作,這個類對AnimatorListener中的函數(shù)都定義了一個空函數(shù)體验靡,這樣我們就只用定義想監(jiān)聽的事件而不用實現(xiàn)每個函數(shù)卻只定義一空函數(shù)體倍宾。
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
oa.setDuration(3000);
oa.addListener(newAnimatorListenerAdapter(){publicvoidon AnimationEnd(Animator animation){
Log.i("Animation","end");
}
});
oa.start();
3.3 ObjectAnimator
繼承自ValueAnimator,要指定一個對象及該對象的一個屬性胜嗓,當(dāng)屬性值計算完成時自動設(shè)置為該對象的相應(yīng)屬性高职,即完成了Property Animation的全部兩步操作。實際應(yīng)用中一般都會用ObjectAnimator來改變某一對象的某一屬性辞州,但用ObjectAnimator有一定的限制怔锌,要想使用ObjectAnimator,應(yīng)該滿足以下條件:
對象應(yīng)該有一個setter函數(shù):set(駝峰命名法)
如上面的例子中变过,像ofFloat之類的工場方法埃元,第一個參數(shù)為對象名,第二個為屬性名媚狰,后面的參數(shù)為可變參數(shù)岛杀,如果values…參數(shù)只設(shè)置了一個值的話,那么會假定為目的值崭孤,屬性值的變化范圍為當(dāng)前值到目的值类嗤,為了獲得當(dāng)前值,該對象要有相應(yīng)屬性的getter方法:get
如果有g(shù)etter方法辨宠,其應(yīng)返回值類型應(yīng)與相應(yīng)的setter方法的參數(shù)類型一致土浸。
如果上述條件不滿足,則不能用ObjectAnimator彭羹,應(yīng)用ValueAnimator代替黄伊。
tv=(TextView)findViewById(R.id.textview1);
btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(newOnClickListener() {
@OverridepublicvoidonClick(View v) {
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
oa.setDuration(3000);
oa.start();
}
});
把一個TextView的透明度在3秒內(nèi)從0變至1。
根據(jù)應(yīng)用動畫的對象或?qū)傩缘牟煌梢螅赡苄枰趏nAnimationUpdate函數(shù)中調(diào)用invalidate()函數(shù)刷新視圖还最。
3.4 通過AnimationSet應(yīng)用多個動畫
AnimationSet提供了一個把多個動畫組合成一個組合的機(jī)制,并可設(shè)置組中動畫的時序關(guān)系毡惜,如同時播放拓轻,順序播放等。
以下例子同時應(yīng)用5個動畫:
播放anim1经伙;
同時播放anim2,anim3,anim4扶叉;
播放anim5勿锅。
AnimatorSet bouncer =newAnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
animatorSet.start();
3.5 TypeEvalutors
根據(jù)屬性的開始、結(jié)束值與TimeInterpolation計算出的因子計算出當(dāng)前時間的屬性值枣氧,android提供了以下幾個evalutor:
IntEvaluator:屬性的值類型為int溢十;
FloatEvaluator:屬性的值類型為float;
ArgbEvaluator:屬性的值類型為十六進(jìn)制顏色值达吞;
TypeEvaluator:一個接口张弛,可以通過實現(xiàn)該接口自定義Evaluator。
自定義TypeEvalutor很簡單酪劫,只需要實現(xiàn)一個方法吞鸭,如FloatEvalutor的定義:
publicclassFloatEvaluatorimplementsTypeEvaluator {publicObject evaluate(floatfraction, Object startValue, Object endValue) {floatstartFloat =((Number) startValue).floatValue();returnstartFloat + fraction * (((Number) endValue).floatValue() -startFloat);
}
}
根據(jù)動畫執(zhí)行的時間跟應(yīng)用的Interplator,會計算出一個0~1之間的因子覆糟,即evalute函數(shù)中的fraction參數(shù)刻剥,通過上述FloatEvaluator應(yīng)該很好看出其意思。
3.6 TimeInterplator
Time interplator定義了屬性值變化的方式滩字,如線性均勻改變造虏,開始慢然后逐漸快等。在Property Animation中是TimeInterplator踢械,在View Animation中是Interplator酗电,這兩個是一樣的魄藕,在3.0之前只有Interplator内列,3.0之后實現(xiàn)代碼轉(zhuǎn)移至了TimeInterplator。Interplator繼承自TimeInterplator背率,內(nèi)部沒有任何其他代碼话瞧。
AccelerateInterpolator ? ? 加速,開始時慢中間加速
DecelerateInterpolator ? 減速寝姿,開始時快然后減速
AccelerateDecelerateInterolator ? 先加速后減速交排,開始結(jié)束時慢,中間加速
AnticipateInterpolator ?反向 饵筑,先向相反方向改變一段再加速播放
AnticipateOvershootInterpolator ? 反向加回彈埃篓,先向相反方向改變,再加速播放根资,會超出目的值然后緩慢移動至目的值
BounceInterpolator ?跳躍架专,快到目的值時值會跳躍,如目的值100玄帕,后面的值可能依次為85部脚,77,70裤纹,80委刘,90,100
CycleIinterpolator 循環(huán),動畫循環(huán)一定次數(shù)锡移,值的改變?yōu)橐徽液瘮?shù):Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator 線性呕童,線性均勻改變
OvershottInterpolator ?回彈,最后超出目的值然后緩慢改變到目的值
TimeInterpolator ? 一個接口罩抗,允許你自定義interpolator拉庵,以上幾個都是實現(xiàn)了這個接口
3.7 當(dāng)Layout改變時應(yīng)用動畫
ViewGroup中的子元素可以通過setVisibility使其Visible、Invisible或Gone套蒂,當(dāng)有子元素可見性改變時(VISIBLE钞支、GONE),可以向其應(yīng)用動畫操刀,通過LayoutTransition類應(yīng)用此類動畫:
transition.setAnimator(LayoutTransition.DISAPPEARING, customDisappearingAnim);
通過setAnimator應(yīng)用動畫烁挟,第一個參數(shù)表示應(yīng)用的情境,可以以下4種類型:
APPEARING 當(dāng)一個元素在其父元素中變?yōu)閂isible時對這個元素應(yīng)用動畫
CHANGE_APPEARING 當(dāng)一個元素在其父元素中變?yōu)閂isible時骨坑,因系統(tǒng)要重新布局有一些元素需要移動撼嗓,對這些要移動的元素應(yīng)用動畫
DISAPPEARING 當(dāng)一個元素在其父元素中變?yōu)镚ONE時對其應(yīng)用動畫
CHANGE_DISAPPEARING ?當(dāng)一個元素在其父元素中變?yōu)镚ONE時,因系統(tǒng)要重新布局有一些元素需要移動欢唾,這些要移動的元素應(yīng)用動畫.
第二個參數(shù)為一Animator且警。
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
此函數(shù)設(shè)置動畫延遲時間,參數(shù)分別為類型與時間礁遣。
3.8 Keyframes
keyFrame是一個 時間/值 對斑芜,通過它可以定義一個在特定時間的特定狀態(tài),即關(guān)鍵幀祟霍,而且在兩個keyFrame之間可以定義不同的Interpolator杏头,就好像多個動畫的拼接,第一個動畫的結(jié)束點是第二個動畫的開始點沸呐。KeyFrame是抽象類醇王,要通過ofInt(),ofFloat(),ofObject()獲得適當(dāng)?shù)腒eyFrame,然后通過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);
上述代碼的意思為:設(shè)置btn對象的width屬性值使其:
開始時 Width=400
動畫開始1/4時 Width=200
動畫開始1/2時 Width=400
動畫開始3/4時 Width=100
動畫結(jié)束時 Width=500
第一個參數(shù)為時間百分比寓娩,第二個參數(shù)是在第一個參數(shù)的時間時的屬性值。
定義了一些Keyframe后呼渣,通過PropertyValuesHolder類的方法ofKeyframe一個PropertyValuesHolder對象棘伴,然后通過ObjectAnimator.ofPropertyValuesHolder獲得一個Animator對象。
用下面的代碼可以實現(xiàn)同樣的效果(上述代碼時間值是線性徙邻,變化均勻):
ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500);
oa.setDuration(2000);
oa.start();
3.9 Animating Views
在View Animation中排嫌,對View應(yīng)用Animation并沒有改變View的屬性,動畫的實現(xiàn)是通過其Parent View實現(xiàn)的缰犁,在View被drawn時Parents View改變它的繪制參數(shù)淳地,draw后再改變參數(shù)invalidate怖糊,這樣雖然View的大小或旋轉(zhuǎn)角度等改變了,但View的實際屬性沒變颇象,所以有效區(qū)域還是應(yīng)用動畫之前的區(qū)域伍伤,比如你把一按鈕放大兩倍,但還是放大這前的區(qū)域可以觸發(fā)點擊事件遣钳。為了改變這一點扰魂,在Android 3.0中給View增加了一些參數(shù)并對這些參數(shù)增加了相應(yīng)的getter/setter函數(shù)(ObjectAnimator要用這些函數(shù)改變這些屬性):
translationX,translationY: View相對于原始位置的偏移量
rotation,rotationX,rotationY: 旋轉(zhuǎn),rotation用于2D旋轉(zhuǎn)角度蕴茴,3D中用到后兩個
scaleX,scaleY: 縮放比
x,y: View的最終坐標(biāo)劝评,是View的left,top位置加上translationX倦淀,translationY
alpha: 透明度
跟位置有關(guān)的參數(shù)有3個蒋畜,以X坐標(biāo)為例,可以通過getLeft(),getX(),getTranslateX()獲得撞叽,若有一Button btn2姻成,布局時其坐標(biāo)為(40,0):
//應(yīng)用動畫之前
btn2.getLeft();//40
btn2.getX();//40
btn2.getTranslationX();//0
//應(yīng)用translationX動畫
ObjectAnimator oa=ObjectAnimator.ofFloat(btn2,"translationX", 200);
oa.setDuration(2000);
oa.start();
/*應(yīng)用translationX動畫后
btn2.getLeft();? ? //40
btn2.getX();? ? //240
btn2.getTranslationX();? ? //200
*/
//應(yīng)用X動畫,假設(shè)沒有應(yīng)用之前的translationX動畫
ObjectAnimator oa=ObjectAnimator.ofFloat(btn2, "x", 200);
oa.setDuration(2000);
oa.start();
/*應(yīng)用X動畫后
btn2.getLeft();? ? //40
btn2.getX();? ? //200
btn2.getTranslationX();? ? //160
*/
無論怎樣應(yīng)用動畫愿棋,原來的布局時的位置通過getLeft()獲得科展,保持不變;
X是View最終的位置糠雨;
translationX為最終位置與布局時初始位置這差才睹。
所以若就用translationX即為在原來基礎(chǔ)上移動多少,X為最終多少
getX()的值為getLeft()與getTranslationX()的和
對于X動畫见秤,源代碼是這樣的:
caseX:
info.mTranslationX = value - mView.mLeft;
break;
Property Animation也可以在XML中定義
- AnimatorSet
-?ValueAnimator
-?ObjectAnimator
XML文件應(yīng)放大/res/animator/中砂竖,通過以下方式應(yīng)用動畫:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator);
set.setTarget(myObject);
set.start();
3.10 ViewPropertyAnimator
如果需要對一個View的多個屬性進(jìn)行動畫可以用ViewPropertyAnimator類真椿,該類對多屬性動畫進(jìn)行了優(yōu)化鹃答,會合并一些invalidate()來減少刷新視圖,該類在3.1中引入突硝。
以下兩段代碼實現(xiàn)同樣的效果:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
myView.animate().x(50f).y(100f);