Android全套動畫使用技巧



1、Android View 動畫框架

Animation框架定義了透明度、旋轉、縮放和位移幾種常見的動畫,控制的整個View,實現原理是每次繪製視圖時View所在ViewGroup中的drawChild函數獲取該View的Animation的Transformation值,而後調用canvas.concat(transformToApply.getMatrix()),經過矩陣運算完成動畫幀。若是沒有完成就繼續調用invalidate()函數,啓動下次繪製來驅動動畫,從而完成整個動畫的繪製。
視圖動畫使用簡單,效果豐富,它提供了AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation四種動畫方式,並提供動畫集合AnimationSet,混合使用多種動畫。在Android3.0以前,視圖動畫一家獨大,但隨着Android3.0以後屬性動畫框架的推出,它的風光就大不如從前。相比屬性動畫,視圖動畫的一個很是大的缺陷就是不具有交互性,當某個元素髮生視圖動畫後,其響應事件的位置還依然在動畫前的地方,因此視圖動畫只能作普通的動畫效果,避免交互的發生。可是它的優勢也很是明顯,即效率比較高且使用方便。android

視圖動畫使用很是簡單,不只能夠經過XML文件來描述一個動畫過程,一樣也可使用代碼來控制整個動畫過程。canvas

(1)、透明度動畫

爲視圖增長透明度的變換動畫。bash

AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
view.startAnimation(aa);複製代碼

(2)、旋轉動畫

爲視圖增長旋轉的變換動畫。app

RotateAnimation ra = new RotateAnimation(0, 360, 100, 100);
ra.setDuration(1000);
view.startAnimation(ra);複製代碼

其參數分別爲旋轉的起始角度和旋轉中心點的座標,固然,能夠經過設置參數來控制旋轉動畫的參考系,這裏設置旋轉動畫的參考系爲中心。框架

RotateAnimation ra1 = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5F, RotateAnimation.RELATIVE_TO_SELF, 0.5F);複製代碼

(3)、位移動畫

爲視圖移動時增長位移動畫。ide

TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
ta.setDuration(1000);
view.startAnimation(ta);複製代碼

(4)、縮放動畫

爲視圖的縮放增長動畫效果函數

ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2);
sa.setDuration(1000);
view.startAnimation(sa);複製代碼

與旋轉動畫同樣,縮放動畫也能夠設置羅芳的中心點,設置中心爲自身中心效果佈局

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)、動畫集合

經過AnimationSet,能夠將動畫以組合的形式展示出來:post

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);複製代碼

能夠直接拷貝運行代碼看效果!動畫

對於動畫事件,Android也提供了對應的監聽回調,代碼:

as.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        //動畫開始
    }

    @Override
    public void onAnimationEnd(Animation animation) {
        //動畫結束
    }

    @Override
    public void onAnimationRepeat(Animation animation) {
        //動畫重複
    }
});複製代碼

2、屬性動畫

因爲Android3.0以前已有的動畫框架Animation存在一些侷限性——動畫改變的只是顯示,並不能響應事件。所以在Android3.0以後,Google就提出了屬性動畫這樣一個新的動畫框架,實現更豐富的效果。

而在Animator框架中使用最多的就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator進行更精細化控制,只控制一個對象的一個屬性值,而使用多個ObjectAnimator組合到AnimatorSet造成一個動畫。並且ObjectAnimator可以自動驅動,能夠調用setFrameDelay(long frameDelay)設置動畫幀之間的間隙時間。最重要的是,屬性動畫經過調用屬性的get、set方法來真實地控制了一個View的屬性值,所以強大的屬性動畫框架,基本能夠實現全部的動畫效果。

(1)、ObjectAnimator

ObjectAnimator是屬性動畫框架中最重要的實行類,建立一個ObjectAnimator只須要經過他的靜態工廠類直接返回一個ObjectAnimator對象。參數包括一個對象和對象的屬性名字,但這個屬性也必須有get和set函數,內部會經過Java反射機制來調用set函數修改對象屬性值。一樣,你也能夠調用setInterpolator設置相應的差值器。

接下來試想一下對一個Button添加一個平移動畫,使用之前的動畫框架平移後將不能觸發點擊事件,點擊的有效區域仍然是原來的地方,點擊移動後的地方是不會有點擊事件發生的。而屬性動畫則不一樣,它真實地改變了一個View的屬性,因此事件響應的區域也一樣發生了改變,這時候點擊移動後的按鈕,就會響應點擊事件了。

屬性動畫平移代碼以下:

ObjectAnimator animator = ObjectAnimator.ofFloat(
        imageView,
        "translationX",
        200F);
animator.setDuration(300);
animator.start();複製代碼

在使用ObjectAnimator的時候,有一點很是重要,那就是要操縱的屬性必須具備get、set方法,否則ObjectAnimator就沒法生效。下面是經常使用的屬性:

  • translationX和translationY:這兩個屬性做爲一種增量控制着View對象從它佈局容器左上角座標開始的位置。
  • rotation、rotationX和rotationY:這個三個屬性控制View對象圍繞支點進行2D和3D旋轉。
  • scaleX和scaleY:這兩個屬性控制着View對象圍繞他的支點進行2D縮放。
  • pivotX和pivotY:這兩個屬性控制着View對象的支點位置,圍繞這個支點進行旋轉和縮放變換處理。默認狀況下,該支點的位置就是View對象的中心點。
  • x和y:這兩個簡單實用的屬性,描述了View對象在它的容器中的最終位置,它是最初的左上角座標和translationX、translationY值的累積和。
  • alpha:表示View對象的alpha透明度。默認值是1(不透明),0表明徹底透明(不可見)。

根據以上得知視圖動畫所實現的動畫效果,這裏基本都已經包含了。

那麼若是一個屬性沒有get、set方法,屬性動畫是否是就一籌莫展了呢?答案是否認的,Google在應用層提供了兩種方案來解決這個問題,一個是經過自定義一個屬性類或者包裝類,來間接地給這個屬性增長get、set方法;或者經過ValueAnimator來實現,ValueAnimator在後面的內容中講到,這個先看看使用包裝類的方法給一個屬性增長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();
    }
}複製代碼

經過以上代碼,就跟一個屬性包裝了一層,並給它提供了get、set方法。使用時只須要操縱包裝類就能夠間接調用到get、set方法了,代碼以下所示:

WrapperView wrapperView = new WrapperView(view);
ObjectAnimator.ofInt(wrapperView, "width", 500).setDuration(5000).start();複製代碼

(2)、PropertyValuesHolder

相似視圖動畫中的AnimationSet,在屬性動畫中,若是針對同一個對象的多個屬性,要同時做用多種動畫,可使用PropertyValuesHolder來實現。好比平移動畫,若是在平移的過程當中同時改變X、Y軸的縮放,能夠這樣實現,代碼:

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 對象控制translationX、scaleX、scaleY這三個屬性,最屌調用ObjectAnimator.ofPropertyValuesHolder方法實現多屬性動畫的共同做用,整個實現方法很是相似AnimatorSet使用。

(3)、ValueAnimator

ValueAnimator在屬性動畫中佔用很是重要的地位,雖然不ObjectAnimator那樣耀眼,但它倒是屬性動畫的核心所在,ObjectAnimator也是繼承自ValueAnimator。

public final class ObjectAnimator extends ValueAnimator複製代碼

ValueAnimator自己不提供任何動畫效果,它更像一個數值發生器,用來產生具備必定規律的數字,從而讓調用者來控制動畫的實現過程,ValueAnimator的通常使用方法:一般在ValueAnimator的AnimatorUpdateListener中監聽數值的變換,完成動畫的變換。

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)、動畫事件的監聽

一個完整的動畫具備Start、Repeat、End、Cancel四個過程,經過Android提供了接口,很方便地監聽到這四個事件:

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();複製代碼

大部分的時候只關心onAnimationEnd事件,因此Android也提供了一個AnimatorListenerAdapter來讓咱們選擇必要的事件進行監聽:

anim.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
    }
});複製代碼

(5)、AnimatorSet

對於一個屬性同時做用多個屬性動畫效果,前面已經使用PropertyValuesHolder實現了這樣的效果。而AnimatorSet不只能實現這樣的效果,同時也能實現更爲精確的順序控制。一樣是實現上面使用PropertyValuesHolder演示的那個動畫效果,若是使用AnimatorSet來實現,那麼代碼以下:

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();複製代碼

在屬性動畫中,AnimatorSet正是經過playTogether()、playSquentially()、animSet.play().width()、defore()、after()這些方法來控制多個動畫的協同工做方式,從而作到對動畫播放順序的精確控制。

(6)、在XML中使用屬性動畫

屬性動畫同視圖動畫同樣,也能夠直接寫在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>複製代碼

前提使用XML定義屬性動畫XML文件必定要放在res/animator/filename.xml文件夾下面才能識別,不然不能識別。發現屬性動畫與視圖動畫在XML文件中的寫法很類似。在程序中使用:

Animator anim = AnimatorInflater.loadAnimator(this,R.animator.filename);
anim.setTarget(view);
anim.start();複製代碼

(7)、View的animate方法

在Android3.0以後,Google給View增長了animate方法來直接驅動屬性動畫,代碼以下:

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();複製代碼

3、Android佈局動畫

佈局動畫是指做用在ViewGroup上,給ViewGroup增長View時添加一個動畫過渡效果。最簡單的佈局動畫是在ViewGroup的XML中,使用以下代碼打開佈局動畫:

android:animateLayoutChanges="true"複製代碼

經過以上設置,當ViewGroup添加到View時,子View會呈現逐漸顯示的過渡效果,不過這個效果是Android默認的顯示的過渡效果,沒法使用自定義動畫來替換這個效果。

還能夠經過使用LayoutAnimatorController類自定義一個子View的過渡效果,添加一個視圖動畫,使得子View出現的時候有一個縮放的動畫效果,代碼:

LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
sa.setDuration(2000);
//設置佈局動畫的顯示
LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f);
//設置佈局動畫
ll.setLayoutAnimation(lac);複製代碼

LayoutAnimationController 的第一個參數,是須要做用的動畫,而第二個參數,則是每一個子View顯示的delay時間。當delay時間不爲0時,能夠設置子View顯示的順序。

//順序
public static final int ORDER_NORMAL  = 0;

//隨機
public static final int ORDER_REVERSE = 1;

//反序
public static final int ORDER_RANDOM  = 2;複製代碼

4、Interpolators——插值器

插值器是動畫一個很是重要的概念,經過插值器Interpolators,能夠定義動畫變換速率,這一點很是相似物理中的加速度,起做用主要是控制目標變量的變化值進行對應的變化。

  • AccelerateDecelerateInterpolator 在動畫開始與介紹的地方速率改變比較慢,在中間的時候加速
  • AccelerateInterpolator 在動畫開始的地方速率改變比較慢,而後開始加速
  • AnticipateInterpolator 開始的時候向後而後向前甩
  • AnticipateOvershootInterpolator 開始的時候向後而後向前甩必定值後返回最後的值
  • BounceInterpolator 動畫結束的時候彈起
  • CycleInterpolator 動畫循環播放特定的次數,速率改變沿着正弦曲線
  • DecelerateInterpolator 在動畫開始的地方快而後慢
  • LinearInterpolator 以常量速率改變
  • OvershootInterpolator 向前甩必定值後再回到原來位置
  • PathInterpolator 路徑插值器

5、自定義動畫

建立自定義動畫只須要實現它的applyTransformation的邏輯就能夠了,不過一般狀況下,還須要覆蓋父類的initalize方法來實現初始化工做。applyTransformation方法以下:

protected void applyTransformation(
        float interpolatedTime,
        Transformation t) {
}複製代碼

第一個參數interpolatedTime是上面說的插值器的時間因子,這個因子是由動畫當前完成的百分比和當前時間所對應的插件所計算得來的,取值範圍在0-1.0。

第二個參數Transformation 是矩陣的封裝類,通常使用這個類來得到當前的局針對想,以下:

final Matrix matrix = t.getMatrix();複製代碼

經過改變得到的matrix對象,能夠將動畫效果實現出來,而對於matrix的變換操做,基本能夠實現任何效果的動畫。對於matrix的介紹能夠查看:深刻理解 Android 中的 Matrix

@Override
protected void applyTransformation(
        float interpolatedTime,
        Transformation t) {
    final Matrix matrix = t.getMatrix();
    //經過matrix的各類操做來實現動畫
}複製代碼

經過模擬電視機關閉的效果來看看簡單的矩陣變化時如何實現動畫效果的。電視機關閉的效果就是讓一個圖片縱向比例不斷縮小便可,對應的矩陣動處理方法以下:

@Override
protected void applyTransformation(
        float interpolatedTime,
        Transformation t) {
    final Matrix matrix = t.getMatrix();
    matrix.preScale(1,
            1 - interpolatedTime,
            mCenterWidth,
            mCenterHeight);
}複製代碼

其中的mCenterWidth、mCenterHeight即爲縮放的中心點,設置爲圖片中心便可。這樣經過一個簡單的矩陣變換,就能夠模擬電視機關閉的動畫。

也能夠設置更精準插值器,並將0到1的時間因子拆分紅不一樣的過程,從而對不一樣的過程採用不一樣的動畫效果。代碼以下:

@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());
    mCenterWidth = width / 2;
    mCenterHeight = height / 2;
}複製代碼

自定義動畫的核心——如何定義動畫的進行過程,代碼:

@Override
protected void applyTransformation(
        float interpolatedTime,
        Transformation t) {
    final Matrix matrix = t.getMatrix();
    mCamera.save();
    // 使用Camera設置旋轉的角度
    mCamera.rotateY(mRotateY * interpolatedTime);
    // 將旋轉變換做用到matrix上
    mCamera.getMatrix(matrix);
    mCamera.restore();
    // 經過pre方法設置矩陣做用前的偏移量來改變旋轉中心
    matrix.preTranslate(mCenterWidth, mCenterHeight);
    matrix.postTranslate(-mCenterWidth, -mCenterHeight);
}複製代碼

經過以上代碼使用Camera類實現動畫效果就是設置三個座標軸的旋轉角度,經過最後兩行代碼能夠改變旋轉時默認旋轉中心。

未完,待續。。。

相關文章
相關標籤/搜索