第七章 Android 動畫機制與使用技巧

Android 群英傳筆記
第一章Android體系與系統(tǒng)架構(gòu)
第二章 Android開發(fā)工具及技巧
第三章 Android控件架構(gòu)與事件攔截機制
第四章 ListView 使用技巧
第五章 Android Scroll 分析
第六章 Android 繪圖機制與屏幕適配
第七章 Android 動畫機制與使用技巧
第八章 Activity與Activity調(diào)用棧分析
第九章 Android 系統(tǒng)信息與安全機制
第十章 Android性能優(yōu)化
本文出自:
http://www.itdecent.cn/u/a1251e598483

Android動畫效果一直是人家中十分重要的一部分,從早期的Android版本中,由于動畫機制和繪圖機制的不健全,Android的人機交互備受詬病,Android從4.X開始,特別是5.X,動畫越來越完善了,Google也開始重視這一方面了,我們本章學(xué)習(xí)的主要內(nèi)容有

  • Android視圖動畫‘
  • Android屬性動畫
  • Android動畫實例
Android View動畫框架

Animation動畫框架定義了透明度,旋轉(zhuǎn),縮放個移動等幾種動畫,而且控制了整個的View,實現(xiàn)原理是每次繪制視圖的時候View所在的ViewGroup中drawChild函數(shù)獲取該View的Animation的Transformation值,然后調(diào)用了canvas.concat方法,通過矩陣運算完成動畫幀,如果動畫沒有完成則繼續(xù)調(diào)用invalidate()方法啟動下回繪制來驅(qū)動動畫,從而完成整個動畫的繪制

視圖動畫使用簡單,效果豐富,它提供了AlphaAnimation,RotateAnimatio,TranslateAnimation,ScaleAnimation四種動畫方式,并提供了Animationset動畫集合,混合使用多種動畫,在Android3.0之前,視圖動畫一家獨大,但隨著Android3.0之后屬性動畫框架的推出它的風(fēng)光就大不如前了。相比屬性動畫,視圖動畫的一個非常大的缺陷就是不具備交互性,當(dāng)某個元件發(fā)生視圖動畫后,其響應(yīng)事件的位置還依然在動畫前的地方,所以視圖動畫只能做普通的顯示效果,避免交互的發(fā)生,但是它的優(yōu)點也非常明顯,即效率比較高且使用方便。視圖動畫使用非常簡單, 不僅可以通過XML文件來描述一個動畫過程,同樣也可以使用代碼來控制整 個動畫過程

視圖動畫

下面這個實例就列舉了一些簡單的視圖動畫使用方法

  • 透明動畫

為視圖增加透明度的變換動畫

AlphaAnimation al = new AlphaAnimation(0,1);
al.setDuration(2000);
alpha.startAnimation(al);
  • 旋轉(zhuǎn)動畫
RotateAnimation ro = new RotateAnimation(0,300,100,100);
 ro.setDuration(2000);
 rotate.setAnimation(ro)
  • 平移動畫
TranslateAnimation tr = new TranslateAnimation(0,200,0,300);
tr.setDuration(2000);
translate.setAnimation(tr);
  • 縮放動畫
 ScaleAnimation sc = new ScaleAnimation(0,2,0,2);
 sc.setDuration(2000);
 scale.setAnimation(sc);
  • 動畫集合
AnimationSet setAnimation = new AnimationSet(true);
setAnimation.setDuration(2000);

AlphaAnimation als = new AlphaAnimation(0,1);
als.setDuration(2000);
setAnimation.addAnimation(als);

RotateAnimation ros = new RotateAnimation(0,300,100,100);
ros.setDuration(2000);
setAnimation.addAnimation(ros);

set.startAnimation(setAnimation);

當(dāng)然,有動畫,就有監(jiān)聽,我們來監(jiān)聽一下動畫,以透明動畫為例

                AlphaAnimation al = new AlphaAnimation(0,1);
                al.setDuration(2000);
                alpha.startAnimation(al);

                al.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        Log.i("Animation","開始");
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        Log.i("Animation","結(jié)束");
                        Toast.makeText(MainActivity.this,"動畫結(jié)束",Toast.LENGTH_LONG).show();
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });

Android屬性動畫分析

屬性動畫在Animator框架里的,用的最多的也就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator進行更精細(xì)化的控制,只控制一個對象的屬性,而使用多個ObjectAnimator組合到AnimatorSet形成一個動畫,而且ObjectAnimator能夠自動驅(qū)動,單證各種好處,我們來看一下

  • ObjectAnimator

ObjectAnimator是屬性動畫框架中最重要的實行類,創(chuàng)建一個ObjectAnimator只需通過他 的靜態(tài)工廠類直接返回一個ObjectAnimator對象,參數(shù)包括一個對象和對象的屬性名字,但這 個屬性必須有g(shù)et和對函數(shù),內(nèi)部會通過Java反射機制來調(diào)用set函數(shù)修改對象屬性值.同樣 你也可以調(diào)用setIn設(shè)置相應(yīng)的差值器。 下面這個小例子就完成了一個非常簡單的平 移動畫,

在前面的講解中說到,以前的動畫框架所產(chǎn)生的動畫,并不能改變事件響應(yīng)的位置,它只是單純地修改了顯示.如果使用舊的視圖動畫產(chǎn)生上面的效果,那么按鈕的實際點擊有效區(qū)依然在原來的地方,點擊移動后的地方是不會有點擊事件發(fā)生的.而屬性動圓則不同,由于它真實地改變了一個View的屬性,所以事件響應(yīng)的區(qū)域也同樣發(fā)生了改變,這時候點擊移動后的按鈕, 就會響應(yīng)點擊事件了

讓我們來看看這個簡單的平移動畫是如何實現(xiàn)的.麻雀雖小五臟俱全,這個簡單的例子基本上就涵蓋了ObjectAnimator的所有知識

ObjectAnimator ob = ObjectAnimator.ofFloat(object,"translationX",300);
               ob.setDuration(2000);
               ob.start();

通過ObjectAnimator的靜態(tài)工廠方法,創(chuàng)建個ObjectAnimator對象,第一個參數(shù)自然是要操縱的view,第二個參數(shù)則是要操縱的屬性 而最后個參數(shù)是一個可變數(shù)組參數(shù),需要傳遞進去該屬性變化的一個取值過程,

不過,在使用ObjectAnimator的時候,有一點是非常重要的,就是操縱的set,get方法,不然ObjectAnimator是無效的,下面我們具體舉一些值

  • translationX和 translationY:這兩個屬性作為一種增量來控制著View對象從它布局容器的左上角坐標(biāo)便宜的位置。

  • rotation、rotationX和rotationY:這三個屬性控制View對象圍繞支點進行2D和3D旋轉(zhuǎn)

  • scaleX和scaleY. 這兩個屬性控制著View對象圍繞它的支點進行2D縮放。

  • pivotX和pivotY:這兩個屬性控制著view對象的支點位置,圍繞這個支點進行旋轉(zhuǎn)和縮放變換處理,默認(rèn)情況下,該支點的位置就是View對象的中心點。

  • x和y這是兩個簡單實用的屬性,它描述了View對象在它的容器中的最終位置,它是最初的左上角坐標(biāo)和 translationX和 translationY值的累計和

  • alpha:它表示View對象的alpha透明度,默認(rèn)值是1(不透明),0代表完全透明(不可見)

特別注意,引號里面的單詞一定要寫正確,不然,看不到效果的
由以上可知,視圖動畫所實現(xiàn)的動畫效果,在這里基本都已經(jīng)包含了,那么如果一個屬性沒有g(shù)et,set方法,屬性動畫是不是就束手無策了答案當(dāng)然是否定的,google在應(yīng)用層提供了兩種方案來解決這個問題, 一個是通過自定義一個屬性類或者包裝類,來間接地給這個屬性增加get方法:或者通過ValusAnimator來實現(xiàn),ValusAnimator在后面的內(nèi)容中會講到, 這里先來看看如何使用包裝類的方法給一個屬性增加set,get方法:

private static class WrapperView {

        private View mTarget;

        public WrapperView(View target) {
            mTarget = target;
        }

        public int getWidth() {
            return mTarget.getLayoutParams().width;
        }

        public void setWidth(int width) {
            mTarget.getLayoutParams().width = width;
            mTarget.requestLayout();
        }
    }

通過上面的代碼就給一個屬性包裝上了一層,并且提供set,get方法,使用時操作就行了

WrapperView vi = new WrapperView(alpha);
ObjectAnimator.ofInt(vi,"width",500).setDuration(2000).start();
  • PropertyValuesHolder

這個類類似視圖動畫中的AnimationSet,就是把動畫給組合起來,在屬性動畫中,如果針對一個對象的多個屬性,就同時需要多個動畫了,可以使用PropertyValuesHolder,來實現(xiàn),比如需要在平移的過程中,同時改變x,y的縮放,可以這樣實現(xiàn)

 PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX",300f);
                PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);
                PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY",1f,0,1f);
                ObjectAnimator.ofPropertyValuesHolder(button3,pvh1,pvh2,pvh3).setDuration(1000).start();
  • ValueAnimator

ValueAnimator這個屬性在動畫當(dāng)中有很大的地位,雖然不像ObjectAnimator那樣,耀眼,但是他確實屬性動畫的核心所在,ObjectAnimator也是繼承自他

public final class ObjectAnimator extends ValueAnimator

ValueAnimator本身不提供任何動畫,他更像是一個數(shù)值發(fā)生器,用來產(chǎn)生一定具有規(guī)律的數(shù)字,從而讓調(diào)用者控制動畫的整個過程,我們舉個例子來說明

                ValueAnimator va = ValueAnimator.ofFloat(0,100);
                //除了 可以ofFloat 也可以ofInt 產(chǎn)生整數(shù),可以在里面處理自己想要的動畫效果
                va.setTarget(value);
                va.setDuration(2000).start();
                va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float values = (float) animation.getAnimatedValue();
                        Log.i("數(shù)值",values+"");
                    }
                });
  • 動畫事件的監(jiān)聽

一個完整的動畫是具有,start,repeat,end,cancel四個過程的,通過Android的接口,我們很容易監(jiān)聽到這幾個事件

             ob.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) {

                    }
                });

當(dāng)然,大部分的場景嗎,我們只關(guān)心動畫結(jié)束,所以,Android也提供了一個AnimatorLisistenerAdapter來讓你自己選擇監(jiān)聽事件

        ob.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                    }
                });
  • AnimatorSet

對于一個屬性同時作用在一個view上,前面已經(jīng)有一個PropertyValuesHolder了,而AnimatorSet不僅能實現(xiàn),而且能更精準(zhǔn)的控制順序,同樣是實現(xiàn)PropertyValuesHolder的動畫,AnimatorSet是這樣實現(xiàn)的

        ObjectAnimator animator1 = ObjectAnimator.ofFloat(alpha, "translationX", 300f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(alpha, "scaleX", 1f, 0, 1f);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(alpha, "scaleY", 1f, 0, 1f);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(2000);
        set.playTogether(animator1,animator2,animator3);
        set.start();

在屬性動畫中,AnimatorSet正是通過playTogether等方法控制多個動畫協(xié)同工作,從而控制播放順序的

  • 在XML中定義動畫

屬性動畫同樣的可以定義在xml中
首先在 res 文件夾下建一個animator 文件夾 在這個文件夾中創(chuàng)建一個animator 類型的xml文件

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="2.0"
    android:valueType="floatType"
    >
</objectAnimator>

在代碼中引用

Animator animator = AnimatorInflater.loadAnimator(AnimationActivity.this,R.animator.scale);
                animator.setTarget(button4);
                animator.start();
  • View的animate方法

在Android3.0,Google給view增加了animate方法直接來驅(qū)動屬性動畫,代碼如下,我們可以發(fā)現(xiàn),其實animate就是屬性動畫的一種縮寫

 button4.animate().alpha(0).y(300).setDuration(2000).withStartAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                }).withEndAction(new Runnable() {
                    @Override
                    public void run() {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {

                            }
                        });
                    }
                }).start();
Android 布局動畫

所謂的布局動畫,就是作用在ViewGruop中給View添加的過渡效果,最簡單的方法是在xml中打開

android:animateLayoutChanges="true"

通過以上代碼設(shè)置, 當(dāng)ViewGroup 添加View 時, 子View 會呈現(xiàn)逐漸顯示的過渡效果, 不過這都是Android自帶的效果,我們還可以通過LayoutAnimationController來定義

   ll = (LinearLayout) findViewById(R.id.ll);
        //設(shè)置過渡動畫
        ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
        sa.setDuration(2000);
        LayoutAnimationController lc = new LayoutAnimationController(sa, 0.5f);
        lc.setOrder(LayoutAnimationController.ORDER_NORMAL);
        //設(shè)置布局動畫
        ll.setLayoutAnimation(lc);

LayoutAnimationController的第一個參數(shù) 是需要作用的動畫,第二個參數(shù),是每個子View顯示的delay 時間,當(dāng)delay 時間不為0時,可以設(shè)置子View 顯示的順序

  • 1.LayoutAnimationController.ORDER_NORMAL 順序
  • 2.LayoutAnimationController.ORDER_RANDOM 隨機
  • 3.LayoutAnimationController.ORDER_REVEESE 反序
  • Interpolators(插值器)

插值器在動畫中是一個非常重要的概念,我們通過插值器可以定義動畫變換速率,這一點非常類似物理中的加速度,其作用主要是目標(biāo)變化對應(yīng)的變化,同樣的一個動畫變換起始值,在不同的插值器的作用下,每個單位時間內(nèi)所達(dá)到的變換值都是不一樣的,例如一個平移動畫,如果使用線性插值器,那么在持續(xù)時間內(nèi)單位時間所移動的距離都是一樣的,如果使用加速度插值器,那么單位時間內(nèi)所移動的速度越來越快,大家如果把插值器的概念理解為一個人進行萬米長跑,規(guī)定一個小時到達(dá),有的人怕時間來不及一開始就加速跑但是到后面速度越來越慢,而有的人開始節(jié)省體力,所以開始跑的比較慢,后來越跑越快直到終點,不管怎么跑,最終他們的都是在規(guī)定的時間到達(dá)終點,唯一不同的是他們的跑的速度不同,通過這個例子,我們可以很好的理解插值器的概念

  • 自定義動畫

創(chuàng)建自定義動畫很簡單,只需要實現(xiàn)applyTransformation的邏輯就可以,不過通常情況下,我們還要覆蓋父類的initialize方法來完成一些初始化工作,

@Override
   protected void applyTransformation(float interpolatedTime, Transformation t) {
       super.applyTransformation(interpolatedTime, t);
   }

第一個參數(shù)interpolatedTime是前面說的插值器的時間因子,這個因子是由動畫當(dāng)前完成的百分比和當(dāng)前時間對應(yīng)的差值計算的,取值范圍在0-1.0,第二個參數(shù)就非常簡單了,她是矩陣的封裝類,一般使用這個類獲取當(dāng)前的矩陣對象,代碼如下

 Matrix matrix = t.getMatrix();

通過改變獲得的matrix 對象,可以將動畫效果實現(xiàn),而對于matrix 的變換操作,基本上可以實現(xiàn)任何效果

@Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {

        Matrix matrix = t.getMatrix();
        matrix.preScale(1, 1 - interpolatedTime, width,height);
        super.applyTransformation(interpolatedTime, t);
    }

當(dāng)然我們可以設(shè)置更加精準(zhǔn)的插值器,,從而對不同的過程采用不同的動畫效果,模擬的更加逼真

接下來我們結(jié)合矩陣,并且使用Canmera來實現(xiàn)一個3D的效果,要注意的是,這里所指的Camera不是相機,而是這個類,他封裝了openGl的3D動畫,我們繼續(xù)用代碼來實現(xiàn)

@Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {

        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(2000);
        setFillAfter(true);
        setInterpolator(new BounceInterpolator());
        w = width / 2;
        h = height / 2;

    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {

        Matrix matrix = t.getMatrix();
    //  matrix.preScale(1, 1 - interpolatedTime, w,h);
        mCamera.save();
        //設(shè)置旋轉(zhuǎn)角度
        mCamera.rotate(0, 180, 360);
        mCamera.restore();
        //通過pre方法設(shè)置矩形作用前的偏移量來改變旋轉(zhuǎn)中心
        matrix.preTranslate(w, h);
        matrix.postTranslate(-w, -h);

        super.applyTransformation(interpolatedTime, t);

    }

通過以上的方法,就可以實現(xiàn)了

Android SVG

  • 可伸縮矢量圖形
  • 定義用于網(wǎng)絡(luò)的基于矢量的圖形
  • 使用xml格式定義圖形
  • 圖片在放大或者改變尺寸的情況下其圖形質(zhì)量不會有所損失
  • 萬維網(wǎng)聯(lián)盟的標(biāo)準(zhǔn)
  • 與諸多DOM和XSL之類的W3C標(biāo)準(zhǔn)是一個整體

SVG在web上應(yīng)用非常廣泛,在Android5.X之前的Android版本上,大家可以通過一些第三方庫在Android中使用SVG,而在Android5.X后,Android中添加了對< path >標(biāo)簽的支持,從而讓開發(fā)者可以使用SVG來創(chuàng)建更加豐富的動畫效果,那么SVG對傳統(tǒng)的Bitmap,究竟有什么好處呢?bitmap通過每個像素點上存儲色彩信息來表達(dá)圖像,而SVG是一個繪圖標(biāo)準(zhǔn),與之相對,最大的優(yōu)勢是SVG放大不會失真,而且bitmap需要不同分辨率適配,SVG不需要

< path >標(biāo)簽

使用< path >標(biāo)簽來創(chuàng)建SVG,就是用指令的方式來控制一支畫筆,列入,移動畫筆來到某一個坐標(biāo)位置,畫一條線,畫一條曲線,結(jié)束,< path >標(biāo)簽所支持的指令大致有一下幾種

M = moveto(M X,Y):將畫筆移動到指定的坐標(biāo)位置,但未發(fā)生繪制

L = lineto(L X,Y):畫直線到指定的位置

H = horizontal lineto( H X):畫水平線到指定的X坐標(biāo)位置

V = vertical lineto(V Y ):畫垂直線到指定的Y坐標(biāo)

C = curveto(C ,X1,Y1,X2,Y2,ENDX,ENDY):三次貝塞爾曲線

S = smooth curveto(S X2,Y2,ENDX,ENDY):三次貝塞爾曲線

Q = quadratic Belzier curve(Q X Y,ENDX,ENDY):二次貝塞爾曲線

T = smooth quadratic Belzier curvrto(T,ENDX,ENDY):映射前面路徑的重點

A = elliptical Are(A RX,RY,XROTATION,FLAG1FLAG2,X,Y):弧線

Z = closepath() 關(guān)閉路徑
使用上面的指令時,需要注意的幾點

  • 坐標(biāo)軸以(0,0)位中心,X軸水平向右,Y軸水平向下
  • 所有指令大小寫均可,大寫絕對定位,參照全局坐標(biāo)系,小寫相對定位,參照父容器坐標(biāo)系
  • 指令和數(shù)據(jù)間的空格可以無視
  • 同一指令出現(xiàn)多次可以用一個
SVG常見指令

L
繪制直線的指令是“L”,代表從當(dāng)前點繪制直線到給定點,“L”之后的參數(shù)是一個點坐標(biāo),如“L 200 400”繪制直線,同時,還可以使用“H”和“V”指令來繪制水平豎直線,后面的參數(shù)是x坐標(biāo)個y坐標(biāo)

M

M指令類似Android繪圖中的path類moveto方法,即代表畫筆移動到某一點,但并不發(fā)生繪圖動作

A
A指令是用來繪制一條弧線,且允許弧線不閉合,可以把A指令繪制的弧度想象成橢圓的某一段A指令一下有七個指令

  • RX,RY指所有的橢圓的半軸大小
  • XROTATION 指橢圓的X軸和水平方向順時針方向的夾角,可以想象成一個水平的橢圓饒中心點順時針旋轉(zhuǎn)XROTATION 的角度
  • FLAG1 只有兩個值,1表示大角度弧度,0為小角度弧度
  • FLAG2 只有兩個值,確定從起點到終點的方向1順時針,0逆時針
    X,Y為終點坐標(biāo)

SVG的指令參數(shù)非常的復(fù)雜,但是再Android中,不需要繪制太多的SVG圖像

關(guān)于SVG 可以參考這片文章,挺好的 http://www.itdecent.cn/p/0555b8c1d26a

Android動畫特效

  • 衛(wèi)星菜單

當(dāng)點擊小紅點的時候,彈出菜單,并且?guī)в幸粋€緩沖的效果,這就是Google在MD中強調(diào)的動畫過渡,要怎么實現(xiàn)這個動畫呢,其實還不是就一個開始一個結(jié)束動畫,看代碼

/**
     * 執(zhí)行動畫
     */
    private void statAnim(){
        ObjectAnimator animator0 = ObjectAnimator.ofFloat(iv0,"alpha",1F,0.5F);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(iv1,"translationY",200F);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(iv2,"translationX",200F);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(iv3,"translationY",-200F);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(iv4,"translationX",-200F);
        AnimatorSet set = new AnimatorSet();
        set.setInterpolator(new BounceInterpolator());
        set.playTogether(animator0,animator1,animator2,animator3,animator4);
        set.start();
        mFlag = false;
    }

下面就是點擊事件

iv0.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                   if (mFlag){
                       statAnim();
                   }else{
                       closeAnim();
                   }
            }
        });
  • 計時器動畫

通過這個示例,我們了解一下ValueAnimator的效果,當(dāng)用戶點擊后,數(shù)字不斷增加,好的,我們開始

package com.lgl.animations;

import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

/**
 * 繪制SVG
 * Created by LGL on 2016/4/16.
 */
public class SVGActivity extends AppCompatActivity {

    private TextView tv;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_svg);

        tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tvTimer(tv);
            }
        });
    }

    private void  tvTimer(final  View view){
        ValueAnimator va = ValueAnimator.ofInt(0,100);
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ( (TextView)view).setText("$"+(Integer)animation.getAnimatedValue());
            }
        });
        va.setDuration(3000);
        va.start();
    }

}

  • 下拉展開動畫

下面我們來實現(xiàn)一個展開的動畫,首先,XML是這樣的

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_blue_bright"
        android:gravity="center_vertical"
        android:onClick="llClick"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/app_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@mipmap/ic_launcher" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:gravity="left"
            android:text="Click me"
            android:textSize="30sp" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/hidden_view"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@android:color/holo_orange_light"
        android:orientation="horizontal"
        android:visibility="gone">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@mipmap/ic_launcher" />

        <TextView
            android:id="@+id/tv_hidden"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="I Am Hidden"
            android:textSize="20sp" />

    </LinearLayout>

</LinearLayout>

為了區(qū)分兩個不同的線性布局,我們給他設(shè)置了不同的顏色背景,

package com.younger.animations;

import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

/**
 * 下拉展開動畫
 * Created by Younger on 2018/03/11.
 */
public class AnimaActivity extends AppCompatActivity {

    private LinearLayout mHiddenView;
    private float mDensity;
    private int mHiddenViewMeasuredHeight;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anima);

        mHiddenView = (LinearLayout) findViewById(R.id.hidden_view);
        //獲取像素密度
        mDensity = getResources().getDisplayMetrics().density;
        //獲取布局的高度
        mHiddenViewMeasuredHeight = (int) (mDensity*40+0.5);
    }

    public  void llClick(View view){
        if (mHiddenView.getVisibility() == View.GONE){
            animOpen(mHiddenView);
        }else{
            animClose(mHiddenView);
        }
    }

    private void animOpen(final  View view){
        view.setVisibility(View.VISIBLE);
        ValueAnimator va = createDropAnim(view,0,mHiddenViewMeasuredHeight);
        va.start();
    }


    private void animClose(final  View view){
        int origHeight = view.getHeight();
        ValueAnimator va = createDropAnim(view,origHeight,0);
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                view.setVisibility(View.GONE);
            }
        });
        va.start();
    }


    private ValueAnimator createDropAnim(final  View view,int start,int end) {
        ValueAnimator va = ValueAnimator.ofInt(start, end);
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
                layoutParams.height = value;
                view.setLayoutParams(layoutParams);
            }
        });
        return  va;
    }

}

好了,就這些

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容