新聞中心
【引自MrXI的博客】 一、Android View 動(dòng)畫框架

創(chuàng)新互聯(lián)建站是一家專業(yè)提供晉中企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、H5建站、小程序制作等業(yè)務(wù)。10年已為晉中眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進(jìn)行中。
Animation框架定義了透明度、旋轉(zhuǎn)、縮放和位移幾種常見(jiàn)的動(dòng)畫,控制的整個(gè)View,實(shí)現(xiàn)原理是每次繪制視圖時(shí)View所在ViewGroup中的drawChild函數(shù)獲取該View的Animation的Transformation值,然后調(diào)用canvas.concat(transformToApply.getMatrix()),通過(guò)矩陣運(yùn)算完成動(dòng)畫幀。如果沒(méi)有完成就繼續(xù)調(diào)用invalidate()函數(shù),啟動(dòng)下次繪制來(lái)驅(qū)動(dòng)動(dòng)畫,從而完成整個(gè)動(dòng)畫的繪制。
視圖動(dòng)畫使用簡(jiǎn)單,效果豐富,它提供了AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation四種動(dòng)畫方式,并提供動(dòng)畫集合AnimationSet,混合使用多種動(dòng)畫。在Android3.0之前,視圖動(dòng)畫一家獨(dú)大,但隨著Android3.0之后屬性動(dòng)畫框架的推出,它的風(fēng)光就大不如從前。相比屬性動(dòng)畫,視圖動(dòng)畫的一個(gè)非常大的缺陷就是不具備交互性,當(dāng)某個(gè)元素發(fā)生視圖動(dòng)畫后,其響應(yīng)事件的位置還依然在動(dòng)畫前的地方,所以視圖動(dòng)畫只能做普通的動(dòng)畫效果,避免交互的發(fā)生。但是它的優(yōu)點(diǎn)也非常明顯,即效率比較高且使用方便。
視圖動(dòng)畫使用非常簡(jiǎn)單,不僅可以通過(guò)XML文件來(lái)描述一個(gè)動(dòng)畫過(guò)程,同樣也可以使用代碼來(lái)控制整個(gè)動(dòng)畫過(guò)程。
(1)、透明度動(dòng)畫
為視圖增加透明度的變換動(dòng)畫。
- AlphaAnimation aa = new AlphaAnimation(0, 1);
- aa.setDuration(1000);
- view.startAnimation(aa);
(2)、旋轉(zhuǎn)動(dòng)畫
為視圖增加旋轉(zhuǎn)的變換動(dòng)畫。
- RotateAnimation ra = new RotateAnimation(0, 360, 100, 100);
- ra.setDuration(1000);
- view.startAnimation(ra);
其參數(shù)分別為旋轉(zhuǎn)的起始角度和旋轉(zhuǎn)中心點(diǎn)的坐標(biāo),當(dāng)然,可以通過(guò)設(shè)置參數(shù)來(lái)控制旋轉(zhuǎn)動(dòng)畫的參考系,這里設(shè)置旋轉(zhuǎn)動(dòng)畫的參考系為中心。
- RotateAnimation ra1 = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5F, RotateAnimation.RELATIVE_TO_SELF, 0.5F);
(3)、位移動(dòng)畫
為視圖移動(dòng)時(shí)增加位移動(dòng)畫。
- TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
- ta.setDuration(1000);
- view.startAnimation(ta);
(4)、縮放動(dòng)畫
為視圖的縮放增加動(dòng)畫效果
- ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2);
- sa.setDuration(1000);
- view.startAnimation(sa);
與旋轉(zhuǎn)動(dòng)畫一樣,縮放動(dòng)畫也可以設(shè)置羅芳的中心點(diǎn),設(shè)置中心為自身中心效果
- ScaleAnimation sa1 = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F);
- sa1.setDuration(1000);
- view.startAnimation(sa1);
(5)、動(dòng)畫集合
通過(guò)AnimationSet,可以將動(dòng)畫以組合的形式展現(xiàn)出來(lái):
- AnimationSet as = new AnimationSet(true);
- as.setDuration(1000);
- AlphaAnimation aa = new AlphaAnimation(0, 1);
- aa.setDuration(1000);
- as.addAnimation(aa);
- RotateAnimation ra = new RotateAnimation(0, 360, 100, 100);
- ra.setDuration(1000);
- as.addAnimation(ra);
- TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
- ta.setDuration(1000);
- as.addAnimation(ta);
- ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2);
- sa.setDuration(1000);
- as.addAnimation(sa);
- view.startAnimation(as);
可以直接拷貝運(yùn)行代碼看效果!
對(duì)于動(dòng)畫事件,Android也提供了對(duì)應(yīng)的監(jiān)聽回調(diào),代碼:
- as.setAnimationListener(new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {
- //動(dòng)畫開始
- }
- @Override
- public void onAnimationEnd(Animation animation) {
- //動(dòng)畫結(jié)束
- }
- @Override
- public void onAnimationRepeat(Animation animation) {
- //動(dòng)畫重復(fù)
- }
- });
二、屬性動(dòng)畫
由于Android3.0之前已有的動(dòng)畫框架Animation存在一些局限性——?jiǎng)赢嫺淖兊闹皇秋@示,并不能響應(yīng)事件。因此在Android3.0之后,Google就提出了屬性動(dòng)畫這樣一個(gè)新的動(dòng)畫框架,實(shí)現(xiàn)更豐富的效果。
而在Animator框架中使用最多的就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator進(jìn)行更精細(xì)化控制,只控制一個(gè)對(duì)象的一個(gè)屬性值,而使用多個(gè)ObjectAnimator組合到AnimatorSet形成一個(gè)動(dòng)畫。而且ObjectAnimator能夠自動(dòng)驅(qū)動(dòng),可以調(diào)用setFrameDelay(long frameDelay)設(shè)置動(dòng)畫幀之間的間隙時(shí)間。最重要的是,屬性動(dòng)畫通過(guò)調(diào)用屬性的get、set方法來(lái)真實(shí)地控制了一個(gè)View的屬性值,因此強(qiáng)大的屬性動(dòng)畫框架,基本可以實(shí)現(xiàn)所有的動(dòng)畫效果。
(1)、ObjectAnimator
ObjectAnimator是屬性動(dòng)畫框架中最重要的實(shí)行類,創(chuàng)建一個(gè)ObjectAnimator只需要通過(guò)他的靜態(tài)工廠類直接返回一個(gè)ObjectAnimator對(duì)象。參數(shù)包括一個(gè)對(duì)象和對(duì)象的屬性名字,但這個(gè)屬性也必須有g(shù)et和set函數(shù),內(nèi)部會(huì)通過(guò)Java反射機(jī)制來(lái)調(diào)用set函數(shù)修改對(duì)象屬性值。同樣,你也可以調(diào)用setInterpolator設(shè)置相應(yīng)的差值器。
接下來(lái)試想一下對(duì)一個(gè)Button添加一個(gè)平移動(dòng)畫,使用以前的動(dòng)畫框架平移后將不能觸發(fā)點(diǎn)擊事件,點(diǎn)擊的有效區(qū)域仍然是原來(lái)的地方,點(diǎn)擊移動(dòng)后的地方是不會(huì)有點(diǎn)擊事件發(fā)生的。而屬性動(dòng)畫則不同,它真實(shí)地改變了一個(gè)View的屬性,所以事件響應(yīng)的區(qū)域也同樣發(fā)生了改變,這時(shí)候點(diǎn)擊移動(dòng)后的按鈕,就會(huì)響應(yīng)點(diǎn)擊事件了。
屬性動(dòng)畫平移代碼如下:
- ObjectAnimator animator = ObjectAnimator.ofFloat(
- imageView,
- "translationX",
- 200F);
- animator.setDuration(300);
- animator.start();
在使用ObjectAnimator的時(shí)候,有一點(diǎn)非常重要,那就是要操縱的屬性必須具有g(shù)et、set方法,不然ObjectAnimator就無(wú)法生效。下面是常用的屬性:
- translationX和translationY:這兩個(gè)屬性作為一種增量控制著View對(duì)象從它布局容器左上角坐標(biāo)開始的位置。
- rotation、rotationX和rotationY:這個(gè)三個(gè)屬性控制View對(duì)象圍繞支點(diǎn)進(jìn)行2D和3D旋轉(zhuǎn)。
- scaleX和scaleY:這兩個(gè)屬性控制著View對(duì)象圍繞他的支點(diǎn)進(jìn)行2D縮放。
- pivotX和pivotY:這兩個(gè)屬性控制著View對(duì)象的支點(diǎn)位置,圍繞這個(gè)支點(diǎn)進(jìn)行旋轉(zhuǎn)和縮放變換處理。默認(rèn)情況下,該支點(diǎn)的位置就是View對(duì)象的中心點(diǎn)。
- x和y:這兩個(gè)簡(jiǎn)單實(shí)用的屬性,描述了View對(duì)象在它的容器中的最終位置,它是最初的左上角坐標(biāo)和translationX、translationY值的累積和。
- alpha:表示View對(duì)象的alpha透明度。默認(rèn)值是1(不透明),0代表完全透明(不可見(jiàn))。
根據(jù)以上得知視圖動(dòng)畫所實(shí)現(xiàn)的動(dòng)畫效果,這里基本都已經(jīng)包含了。
那么如果一個(gè)屬性沒(méi)有g(shù)et、set方法,屬性動(dòng)畫是不是就束手無(wú)策了呢?答案是否定的,Google在應(yīng)用層提供了兩種方案來(lái)解決這個(gè)問(wèn)題,一個(gè)是通過(guò)自定義一個(gè)屬性類或者包裝類,來(lái)間接地給這個(gè)屬性增加get、set方法;或者通過(guò)ValueAnimator來(lái)實(shí)現(xiàn),ValueAnimator在后面的內(nèi)容中講到,這個(gè)先看看使用包裝類的方法給一個(gè)屬性增加get、set方法,代碼如下:
- private static class WrapperView {
- private View mTarget;
- public WrapperView(View mTarget) {
- this.mTarget = mTarget;
- }
- public int getWidth() {
- return mTarget.getLayoutParams().width;
- }
- public void setWidth(int width) {
- mTarget.getLayoutParams().width = width;
- mTarget.requestLayout();
- }
- }
通過(guò)以上代碼,就跟一個(gè)屬性包裝了一層,并給它提供了get、set方法。使用時(shí)只需要操縱包裝類就可以間接調(diào)用到get、set方法了,代碼如下所示:
- WrapperView wrapperView = new WrapperView(view);
- ObjectAnimator.ofInt(wrapperView, "width", 500).setDuration(5000).start();
(2)、PropertyValuesHolder
類似視圖動(dòng)畫中的AnimationSet,在屬性動(dòng)畫中,如果針對(duì)同一個(gè)對(duì)象的多個(gè)屬性,要同時(shí)作用多種動(dòng)畫,可以使用PropertyValuesHolder來(lái)實(shí)現(xiàn)。比如平移動(dòng)畫,如果在平移的過(guò)程中同時(shí)改變X、Y軸的縮放,可以這樣實(shí)現(xiàn),代碼:
- PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 300);
- PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
- PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
- ObjectAnimator.ofPropertyValuesHolder(pvh1, pvh2, pvh3).setDuration(1000).start();
在代碼中,分別使用PropertyValuesHolder 對(duì)象控制translationX、scaleX、scaleY這三個(gè)屬性,最屌調(diào)用ObjectAnimator.ofPropertyValuesHolder方法實(shí)現(xiàn)多屬性動(dòng)畫的共同作用,整個(gè)實(shí)現(xiàn)方法非常類似AnimatorSet使用。
(3)、ValueAnimator
ValueAnimator在屬性動(dòng)畫中占用非常重要的地位,雖然不ObjectAnimator那樣耀眼,但它卻是屬性動(dòng)畫的核心所在,ObjectAnimator也是繼承自ValueAnimator。
- public final class ObjectAnimator extends ValueAnimator
ValueAnimator本身不提供任何動(dòng)畫效果,它更像一個(gè)數(shù)值發(fā)生器,用來(lái)產(chǎn)生具有一定規(guī)律的數(shù)字,從而讓調(diào)用者來(lái)控制動(dòng)畫的實(shí)現(xiàn)過(guò)程,ValueAnimator的一般使用方法:通常在ValueAnimator的AnimatorUpdateListener中監(jiān)聽數(shù)值的變換,完成動(dòng)畫的變換。
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100);
- valueAnimator.setTarget(imageView);
- valueAnimator.setDuration(1000).start();
- valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- Float value = (Float) animation.getAnimatedValue();
- }
- });
(4)、動(dòng)畫事件的監(jiān)聽
一個(gè)完整的動(dòng)畫具有Start、Repeat、End、Cancel四個(gè)過(guò)程,通過(guò)Android提供了接口,很方便地監(jiān)聽到這四個(gè)事件:
- ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "alpha", 0.5F);
- anim.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- }
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
- });
- anim.start();
大部分的時(shí)候只關(guān)心onAnimationEnd事件,所以Android也提供了一個(gè)AnimatorListenerAdapter來(lái)讓我們選擇必要的事件進(jìn)行監(jiān)聽:
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- }
- });
(***nimatorSet
對(duì)于一個(gè)屬性同時(shí)作用多個(gè)屬性動(dòng)畫效果,前面已經(jīng)使用PropertyValuesHolder實(shí)現(xiàn)了這樣的效果。而AnimatorSet不僅能實(shí)現(xiàn)這樣的效果,同時(shí)也能實(shí)現(xiàn)更為精確的順序控制。同樣是實(shí)現(xiàn)上面使用PropertyValuesHolder演示的那個(gè)動(dòng)畫效果,如果使用AnimatorSet來(lái)實(shí)現(xiàn),那么代碼如下:
- ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 300f);
- ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0f, 1f);
- ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, 0f, 1f);
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.setDuration(1000);
- animatorSet.playTogether(objectAnimator, objectAnimator1, objectAnimator2);
- animatorSet.start();
在屬性動(dòng)畫中,AnimatorSet正是通過(guò)playTogether()、playSquentially()、animSet.play().width()、defore()、after()這些方法來(lái)控制多個(gè)動(dòng)畫的協(xié)同工作方式,從而做到對(duì)動(dòng)畫播放順序的精確控制。
(6)、在XML中使用屬性動(dòng)畫
屬性動(dòng)畫同視圖動(dòng)畫一樣,也可以直接寫在XML文件中,代碼:
- android:duration="1000"
- android:propertyName="scaleX"
- android:valueFrom="1.0"
- android:valueTo="2.0"
- android:valueType="floatType">
前提使用XML定義屬性動(dòng)畫XML文件一定要放在res/animator/filename.xml文件夾下面才能識(shí)別,否則不能識(shí)別。發(fā)現(xiàn)屬性動(dòng)畫與視圖動(dòng)畫在XML文件中的寫法很相似。在程序中使用:
- Animator anim = AnimatorInflater.loadAnimator(this,R.animator.filename);
- anim.setTarget(view);
- anim.start();
(7)、View的animate方法
在Android3.0之后,Google給View增加了animate方法來(lái)直接驅(qū)動(dòng)屬性動(dòng)畫,代碼如下:
- imageView.animate()
- .alpha(0)
- .y(300)
- .setDuration(300)
- .withStartAction(new Runnable() {
- @Override
- public void run() {
- }
- })
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- }
- });
- }
- }).start();
三、Android布局動(dòng)畫
布局動(dòng)畫是指作用在ViewGroup上,給ViewGroup增加View時(shí)添加一個(gè)動(dòng)畫過(guò)渡效果。最簡(jiǎn)單的布局動(dòng)畫是在ViewGroup的XML中,使用如下代碼打開布局動(dòng)畫:
- android:animateLayoutChanges="true"
通過(guò)以上設(shè)置,當(dāng)ViewGroup添加到View時(shí),子View會(huì)呈現(xiàn)逐漸顯示的過(guò)渡效果,不過(guò)這個(gè)效果是Android默認(rèn)的顯示的過(guò)渡效果,無(wú)法使用自定義動(dòng)畫來(lái)替換這個(gè)效果。
還可以通過(guò)使用LayoutAnimatorController類自定義一個(gè)子View的過(guò)渡效果,添加一個(gè)視圖動(dòng)畫,使得子View出現(xiàn)的時(shí)候有一個(gè)縮放的動(dòng)畫效果,代碼:
- LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
- ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
- sa.setDuration(2000);
- //設(shè)置布局動(dòng)畫的顯示
- LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f);
- //設(shè)置布局動(dòng)畫
- ll.setLayoutAnimation(lac);
LayoutAnimationController 的***個(gè)參數(shù),是需要作用的動(dòng)畫,而第二個(gè)參數(shù),則是每個(gè)子View顯示的delay時(shí)間。當(dāng)delay時(shí)間不為0時(shí),可以設(shè)置子View顯示的順序。
- //順序
- public static final int ORDER_NORMAL = 0;
- //隨機(jī)
- public static final int ORDER_REVERSE = 1;
- //反序
- public static final int ORDER_RANDOM = 2;
四、Interpolators——插值器
插值器是動(dòng)畫一個(gè)非常重要的概念,通過(guò)插值器Interpolators,可以定義動(dòng)畫變換速率,這一點(diǎn)非常類似物理中的加速度,起作用主要是控制目標(biāo)變量的變化值進(jìn)行對(duì)應(yīng)的變化。
- AccelerateDecelerateInterpolator 在動(dòng)畫開始與介紹的地方速率改變比較慢,在中間的時(shí)候加速
- AccelerateInterpolator 在動(dòng)畫開始的地方速率改變比較慢,然后開始加速
- AnticipateInterpolator 開始的時(shí)候向后然后向前甩
- AnticipateOvershootInterpolator 開始的時(shí)候向后然后向前甩一定值后返回***的值
- BounceInterpolator 動(dòng)畫結(jié)束的時(shí)候彈起
- CycleInterpolator 動(dòng)畫循環(huán)播放特定的次數(shù),速率改變沿著正弦曲線
- DecelerateInterpolator 在動(dòng)畫開始的地方快然后慢
- LinearInterpolator 以常量速率改變
- OvershootInterpolator 向前甩一定值后再回到原來(lái)位置
- PathInterpolator 路徑插值器
未完,待續(xù)。。。
五、開源代碼庫(kù)
***再分享一個(gè)自己積攢很久的代碼庫(kù),只有你想不到,沒(méi)有用不到的,歡迎star
https://github.com/xijiufu
由于github服務(wù)器在美國(guó),有時(shí)訪問(wèn)很慢,還提供了開源中國(guó)地址庫(kù),2個(gè)倉(cāng)庫(kù)代碼均同步更新:
http://git.oschina.net/xijiufu
網(wǎng)頁(yè)題目:Android全套動(dòng)畫使用技巧
新聞來(lái)源:http://www.dlmjj.cn/article/cdocdic.html


咨詢
建站咨詢
