動(dòng)畫可以分為三類:View動(dòng)畫,幀動(dòng)畫,屬性動(dòng)畫。
一、View動(dòng)畫
1.View動(dòng)畫包括四種:平移動(dòng)畫,縮放動(dòng)畫,旋轉(zhuǎn)動(dòng)畫,透明度動(dòng)畫。分別對(duì)應(yīng)著Animation的四個(gè)子類:TranslateAnimation,ScaleAnimation,RotateAnimation,AlphaAnimation。幀動(dòng)畫其實(shí)也是View動(dòng)畫的一種。
2.View動(dòng)畫是對(duì)View的影像做動(dòng)畫,并不是真正的改變View的位置等狀態(tài)。通過View動(dòng)畫將View平移后,新位置不能觸發(fā)點(diǎn)擊事件,老位置可以。
3.使用View動(dòng)畫,在動(dòng)畫完成后,有時(shí)候會(huì)出現(xiàn)View無法隱藏的現(xiàn)象,即設(shè)置setVisiable(View.GONE)沒有效果,這個(gè)時(shí)候只需要調(diào)用view.clearAnimation()清除View動(dòng)畫即可解決此問題。
4.View動(dòng)畫的使用:
通過XMl定義:Animation animation = AnimationUtils.loadAnimation(context,resId);
view.startAnimation(animation);
通過純代碼:
AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaAnimation.setDuration(300);
view.startAnimation(alphaAnimation);
為動(dòng)畫設(shè)置監(jiān)聽:
animation.setAnimationListener(new Animation.AnimationListener());
5.自定義View動(dòng)畫:
繼承Animation類,重寫initialize和applyTransformation方法,在initialize方法中做一些初始化工作,在applyTransformation中進(jìn)行相應(yīng)的矩陣變換。很多時(shí)候需要用到Camera來簡(jiǎn)化矩陣變換的過程,需要用到數(shù)學(xué)上面的東西。實(shí)際開發(fā)中很少用到自定義View動(dòng)畫。
二、幀動(dòng)畫
1.幀動(dòng)畫是順序播放一組預(yù)先定義好的圖片,類似于電影播放。對(duì)應(yīng)于AnimationDrawable類。
XML中的定義方式如下(在drawable文件夾中):
然后將上訴Drawable作為View的背景并通過AnimationDrawable來播放:
view.setBackgroundResource(R.drawable.resid);
AnimationDrawable drawable = view.getBackground();
drawable.start();
2.幀動(dòng)畫使用比較簡(jiǎn)單,但是比較容易引起OOM,所以在使用幀動(dòng)畫時(shí)應(yīng)盡量避免使用過多尺寸較大的圖片。
3.View動(dòng)畫的一個(gè)特殊使用場(chǎng)景,就是為ViewGroup中的所有子元素添加出場(chǎng)效果,需要用到LayoutAnimation。
定義LayoutAnimation:
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/anim_item">
其中anim_item就是具體的View動(dòng)畫,然后為ViewGroup指定android:layoutAnimation屬性 android:layoutAnimation=“@anim/layout_animation”;
4.除了在XML中指定LayoutAnimation外,還可以通過LayoutAnimationController來實(shí)現(xiàn):
Animation animation = AnimationUtils.loadAnimation(context,resid);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
viewGroup.setLayoutAnimation(controller);
5.Activity的切換效果:
調(diào)用overridePendingTransition(resid,resid),但是必須在startActivity跟finish之后調(diào)用才有效果!
三、屬性動(dòng)畫
1.屬性動(dòng)畫是API 11(3.1) 新加入的特性,和View動(dòng)畫不同,它對(duì)作用對(duì)象進(jìn)行了擴(kuò)展,屬性動(dòng)畫可以對(duì)任何對(duì)象做動(dòng)畫,甚至還可以沒有對(duì)象。
動(dòng)畫默認(rèn)時(shí)間間隔300ms,默認(rèn)幀率10ms/幀。其可以達(dá)到的效果是:在一個(gè)時(shí)間間隔內(nèi)完成對(duì)象從一個(gè)屬性值到另一個(gè)屬性值的改變。
2.比較常用的幾個(gè)動(dòng)畫類:ValueAnimator,ObjectAnimator,AnimatorSet。其中ObjectAnimator繼承自ValueAnimator,AnimatorSet和ValueAnimator都繼承自Animator。
AnimatorSet是個(gè)動(dòng)畫集合,可以定義一組動(dòng)畫。
3.Animator是個(gè)抽象類,實(shí)現(xiàn)了Cloneable接口,Cloneable接口里面什么都沒有。
4.ValueAnimator不能對(duì)具體的某個(gè)屬性做動(dòng)畫,但是可以對(duì)一個(gè)值做動(dòng)畫,就是實(shí)現(xiàn)值的漸變。例如:ValueAnimator.ofInt(1.100)。具體的對(duì)某個(gè)屬性值的動(dòng)畫的實(shí)現(xiàn),在它的子類ObjectAnimator中。不過可以通過ValueAnimator對(duì)值的漸變,結(jié)合AnimatorUpdateListener可以做很多事情(包括實(shí)現(xiàn)屬性動(dòng)畫)。
5.使用方法示例:
通過代碼:ObjectAnimator.ofFloat(view,"propertyName",value).start();
通過XML:屬性動(dòng)畫需要定義在res/animator/目錄下面,語(yǔ)法如下:
android:ordering="together">
android:propertyName="x"
android:duration="300"
android:valueTo="200"
android:valueType="floatType"/>
android:propertyName="y"
android:duration="300"
android:valueTo="300"
android:valueType="floatType"/>
一個(gè)下面可以包含多個(gè)。
AnimatorSet set = AnimatorSet.loadAnimator(context,resid);
set.setTarget(view);
set.start();
6.插值器與估值器
插值器:根據(jù)時(shí)間流逝的百分比來計(jì)算出當(dāng)前屬性值改變的百分比。TimeInterpolator
系統(tǒng)預(yù)置的有LinearInterpolator(線性插值器:勻速動(dòng)畫)、AccelerateDecelerateInterpolator(加速減速插值器:動(dòng)畫兩頭慢,中間快)、DecelerateInterpolator(減速插值器:動(dòng)畫越來越慢)等。
這些插值器都繼承自BaseInterpolator,BaseInterpolator實(shí)現(xiàn)了Interpolator接口,而Interpolator幾口繼承自TimeInterpolator接口。TimeInterpolator接口定義一個(gè)方法叫:
public float getInterpolation(float intput); 所以自定義插值器的話,只需要實(shí)現(xiàn)Interpolator或者TimeInterpolator接口。
估值器:根據(jù)當(dāng)前屬性改變的百分比來計(jì)算改變后的屬性值。TypeEvaluator
系統(tǒng)預(yù)置的估值器有IntEvaluator(針對(duì)整型屬性)、FloatEvaluator(針對(duì)浮點(diǎn)型)、ArgbEvaluator(針對(duì)Color屬性)。
它們都實(shí)現(xiàn)了TypeEvaluator接口,TypeEvaluator接口中定義了一個(gè)方法:
public T evaluate(float fraction, T startValue, T endValue);
7.屬性動(dòng)畫要求對(duì)象的該屬性必須有set方法,get方法可選(如果提供了動(dòng)畫的初始值,則不需要get方法,若沒有提供初始值,那么系統(tǒng)會(huì)調(diào)用get方法獲取初始值)。
8.對(duì)任意屬性做動(dòng)畫:如果對(duì)象沒有該屬性的set或者get方法,可以通過如下3種方式解決:
①:給對(duì)象加上get和set方法,如果有權(quán)限的話。
②:用一個(gè)類來包裝原始對(duì)象,間接為其提供get,set方法。(此方法比較常用)
③:采用ValueAnimator,監(jiān)聽動(dòng)畫過程,自己實(shí)現(xiàn)屬性的改變。
關(guān)于方法2的例子:
例如如果對(duì)Button的width屬性做動(dòng)畫,但是Button的width的set方法是設(shè)置最大跟最小寬度,而不是改變其寬度。get方法是獲取寬度。這樣的話直接對(duì)width屬性做動(dòng)畫是沒有效果的,因?yàn)楦静皇窃O(shè)置的那個(gè)我們想改變的寬度。這樣我們可以通過一個(gè)類去包裝Button,然后在這個(gè)類的setWidth方法中,去
button.getLayoutParams().width = width.
button.requestLayout();
這樣就間接的給Button的寬度做了動(dòng)畫。因?yàn)橹苯訛檫@個(gè)寬度去加set方法是行不通的,Button封裝在SDK中,我們改變不了。
9.在動(dòng)畫的內(nèi)部,get,set方法的調(diào)用是通過反射來實(shí)現(xiàn)的。
注意:屬性動(dòng)畫必須運(yùn)行在有Looper的線程中,否則會(huì)拋出“Animators may only be run on Looper threads”異常。