Android 動畫(續)

該文章是一個系列文章,是本人在Android開發的漫漫長途上的一點感想和記錄,我會盡可能按照先易後難的順序進行編寫該系列。該系列引用了《Android開發藝術探索》以及《深刻理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相關知識,另外也借鑑了其餘的優質博客,在此向各位大神表示感謝,膜拜!!!android


前言

上一篇文章呢,咱們說了關於View動畫的那些事,這裏也在總結一下,使用View動畫時須要注意如下4點:(更多詳情請參看個人上一篇博客。)git

  1. View動畫的座標系:View動畫說究竟是View的一系列運動,既然是運動,那麼參照物(座標系)是很重要的。
  2. View動畫的使用場景:View動畫的主體是View,更準確的說是View的副本(影子),View動畫更改的只是顯示,其x,y座標仍然沒有改變,響應事件的位置沒有改變,也就是說view自己並無改變。也所以,不要使用View動畫作交互性操做,例如點擊。
  3. 自定義View動畫的步驟:若是咱們不知足於系統已經定義好的Animation,=,能夠自定義本身的Animation,重寫initializeapplyTransformation這兩個方法便可。
  4. Matrix:接着上一點說,若是想要掌握高級的酷炫的動畫效果,那麼理解Android View動畫的矩陣變換的實質是必經之路。

那麼本章呢是來介紹Android動畫的另一個大類屬性動畫github

屬性動畫簡介

 屬性動畫是API11新加入的特性,和View動畫不一樣,它能夠對任何對象作動畫,甚至還能夠沒有對象,動畫默認時間間隔300ms,默認幀率10ms/幀。其能夠達到的效果是:在一個時間間隔內完成對對象從一個屬性值到另外一個屬性值得改變。經常使用屬性動畫類ValueAnimator、ObjectAnimator和AnimationSet,其中ObjectAnimator繼承於ValueAnimator.
 
注:gihub上JakeWharton大神對API11以前作了屬性動畫的兼容,它的原理其實也很簡單,主要就是判斷當前sdk版本,若是大於API11,那麼就調用官方的API,不然本身實現動畫效果。另外,在API使用方面,它與官方的屬性動畫基本一致。另外,在API使用方面,它與官方的屬性動畫基本一致。好比ObjectAnimator、ValueAnimator等等。 感興趣的同窗能夠訪問該項目的github網址NineOldAndroidsapp

屬性動畫的使用

Java代碼實現
例如改變一個對象(obj)的translationY屬性,能夠寫爲ide

ValueAnimator.ofFloat(obj,"translationY",100);

XML實現(屬性動畫的XML描述語法的固定格式)動畫

<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering=["sequentially"|"together"]>
    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float|int|color"
        android:valueTo="float|int|color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["restart"|"reverse"]
        android:valueType=["colorType"|"intType"]>

    </objectAnimator>
    <animator
        android:duration="int"
        android:valueFrom="float|int|color"
        android:valueTo="float|int|color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["restart"|"reverse"]
        android:valueType=["colorType"|"intType"]>
        
    </animator>
    ...
</set>

不少屬性都是見名知義的,下面呢簡單介紹一下各屬性名稱的含義。
屬性動畫的核心類有3個類,AnimatorSet,ObjectAnimator以及ValueAnimatorthis

  1. XML文件中的 <set>標籤對應AnimatorSet, <set>標籤的ordering屬性有2個候選值"sequentially"|"together",分別表示 <set>標籤內的動畫是按照先後順序播放和同時播放。
  2. <animatior>對應ValueAnimator,

android:duration:表示動畫的時長
android:valueFrom:表示屬性的起始值
android:valueTo:表示屬性的結束值
android:startOffset:表示動畫的延遲時間,動畫開始後,須要延遲多少毫秒後纔會真正播放該動畫
android:repeatCount:表示動畫的重複次數,默認值是0,爲-1時,表示無限循環。
android:repeatMode:表示動畫的重複播放模式,restart表示動畫每次都是從新開始播放,reverse表示動畫第1 次播放完畢後,第2次會逆向播放,第3次又從頭開始播放,以此類推lua

  1. <objectAnimator>對應ObjectAnimator,

android:propertyName:表示屬性動畫做用對象的屬性名稱
android:valueType:表示android:propertyName的值的類型,分爲intType,和floatType,分別表明整型數值和浮點型數值,若android:propertyName指定的屬性表示的是顏色,那麼無需指定android:valueType,系統會自動適配
其餘屬性的含義與上面的<animatior>一致。rest

屬性動畫的進階

咱們先來看一個需求:要求對一個Button作動畫,要求讓其寬度從原始寬度增長到500px。這也太簡單了,code

Button mButton = (Button) findViewById(R.id.button);
ObjectAnimator.ofInt(mButton,"width",500).setDuration(1000).start();

程序運行,可是卻沒有效果,這是爲何呢,仔細想一想沒效果也是應該的,由於你隨便傳遞了一個屬性名稱過去,輕則動畫沒有效果,重則直接Crash。那麼這個號稱能夠對任意屬性作動畫的屬性動畫使用的時候有哪些須要注意的地方呢

  1. 屬性動畫要求動畫的做用對象提供該屬性的get和set方法,
  2. 屬性的改變必須經過某種方法反映出來,好比會帶來UI的修改之類的

以上的條件缺一不可
這時又有一個問題若是想要對一個對象的屬性作動畫,可是屬性又沒有對應的get和set方法怎麼辦呢??

歸納來說有以下3種解決辦法:

  1. 給你的對象加上get和set方法,若是你有權限的話。而這個方法對於Android SDK內部實現的類就不可行,這個方法是最簡單的,可是每每是不可行的。
  2. 用一個類包裝原始對象,間接爲其提供get和set方法
  3. 採用ValueAnimator,監聽動畫過程,本身實現屬性的改變

    下面仍以上面Button的寬度動畫做爲需求給出方法2,3的解決代碼
    方法2:

mButton = (Button) findViewById(R.id.button);
ObjectAnimator.ofInt(new ViewWrapper(mButton),"width",500).setDuration(1000).start();

private class ViewWrapper{
        private View mTarget;

        public ViewWrapper(View mTarget) {
            this.mTarget = mTarget;
        }


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

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

方法3:

使用方法3以前,咱們先來看屬性動畫的監聽器AnimatorUpdateListener和AnimatorListener

屬性動畫的監聽器AnimatorUpdateListener和AnimatorListener

AnimatorUpdateListener

public static interface AnimatorListener {
   
    void onAnimationStart(Animator animation);

    
    void onAnimationEnd(Animator animation);

 
    void onAnimationCancel(Animator animation);

   
    void onAnimationRepeat(Animator animation);
}

如上代碼所示AnimatorListener監聽了動畫的開始、結束、取消和重複播放,同時系統提供了AnimatorListenerAdapter適配器方便咱們使用,咱們能夠繼承這個類並有選擇的實現方法。

AnimatorListener

public static interface AnimatorUpdateListener {
      /**
       * <p>Notifies the occurrence of another frame of the animation.</p>
       *
       * @param animation The animation which was repeated.
       */
      void onAnimationUpdate(ValueAnimator animation);
}

如上圖所示,AnimatorUpdateListener 監聽了動畫的整個過程,動畫每播放一幀,onAnimationUpdate就被調用一次,
下面就來看一下如何使用上面的屬性動畫的監聽器來實現屬性動畫

mButton = (Button) findViewById(R.id.button);
performAnimate(mButton, mButton.getWidth(), 500);

private void performAnimate(final View target, final int start, final int end) {

    ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

        // 持有一個IntEvaluator對象,方便下面估值的時候使用
        private IntEvaluator mEvaluator = new IntEvaluator();

        @Override
        public void onAnimationUpdate(ValueAnimator animator) {
            // 得到當前動畫的進度值,整型,1-100之間
            int currentValue = (Integer) animator.getAnimatedValue();
            Log.d(TAG, "current value: " + currentValue);

            // 得到當前進度佔整個動畫過程的比例,浮點型,0-1之間
            float fraction = animator.getAnimatedFraction();
            // 直接調用整型估值器經過比例計算出寬度,而後再設給Button
            target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
            target.requestLayout();
        }
    });

    valueAnimator.setDuration(5000).start();
}

使用動畫的注意事項

  1. OOM問題,此類問題主要出如今幀動畫中,幀動畫中若是使用大量圖片,則可能會形成OOM問題,避免的方法同理,最好不要在幀動畫中使用大量大尺寸的圖片
  2. View動畫的問題,View動畫的做用主題其實是View的影子,因此View動畫不適合作有交互性點擊的動畫,另外View動畫也不能真正改變View的狀態,因此有的時候會出現動畫結束後,View.setVisibily(VIEW.GONE)失效,或者其餘異常狀況,使用View.clearAnimation()清除動畫便可
  3. 內存泄露,在屬性動畫中有一類無限循環的動畫,這類動畫要在Activity銷燬以前及時中止,不然會形成Activity沒法回收致使內存泄漏。

本篇總結

本章呢接着上一篇說了Android動畫的另一個大類屬性動畫,至此Android動畫相關的文章完結,因筆者水平有限,因此有不當之處還請指出


此致,敬禮

相關文章
相關標籤/搜索