Android 中關於屬性動畫的一些思考,或許能爲你解決一定的性能問題

========================================================
作者:qiujuer
博客:blog.csdn.net/qiujuer
網站:www.qiujuer.net
開源庫:Genius-Android
轉載請註明出處:http://blog.csdn.net/qiujuer/article/details/42531485

——學之開源,用於開源;初學者的心態,與君共勉!
========================================================

用動畫用的久了漸漸的喜歡上她了,雖然它或許並不是女的,但我希望是~~

用的久了,我漸漸的思考性能的問題了;在我的一篇([Material Design] MaterialButton 效果進階 動畫自動移動進行對齊效果)介紹按鈕點擊特效的文章中使用了大量的屬性動畫,但是在後來我想了很久,其是只需要一個屬性動畫就能解決所有問題。

下面咱們來說說怎麼把多個屬性動畫合成一個。

開始

一般來說,我們在自定義控件或者控制一些移動操作的時候會使用到這樣的屬性動畫,其是屬性動畫並不是想象中那麼難,只要看看用法舉一反三用用就會了~

    private float paintX = 0;
    private float paintY = 0;

    private Property<MyView, Float> PaintYProperty = new Property<MyView, Float>(Float.class, "paintY") {
        @Override
        public Float get(MyView object) {
            return object.paintY;
        }

        @Override
        public void set(MyView object, Float value) {
            object.paintY = value;
        }
    };

    private Property<MyView, Float> PaintXProperty = new Property<MyView, Float>(Float.class, "paintX") {
        @Override
        public Float get(MyView object) {
            return object.paintX;
        }

        @Override
        public void set(MyView object, Float value) {
            object.paintX = value;
        }
    };

    private void start() {
        //PaintX
        ObjectAnimator aPaintX = ObjectAnimator.ofFloat(this, PaintXProperty, 0, 100);
        //PaintY
        ObjectAnimator aPaintY = ObjectAnimator.ofFloat(this, PaintYProperty, 0, 100);
        //AnimatorSet
        AnimatorSet set = new AnimatorSet();
        set.playTogether(aPaintX, aPaintY);
        set.start();
    }

在上述的中我們建立了一個關於座標的屬性動畫,一般來說座標含有XY,所以我們定義了兩個屬性動畫;然後打包到一個 AnimatorSet 中管理。至於 AnimatorSet 是什麼?你可以理解爲這個類是一個屬性的管理類,你可以添加 N 多的動畫到其中,然後統一調度開啓停止;在 AnimatorSet 中維護着一個動畫隊列。

在上面雖然最後打包到了 AnimatorSet 中進行統一調度,但是你看看 AnimatorSet 中的部分源碼你就知道其最後也是啓動每一個的屬性動畫進行啓動的。

這也就是我們今天需要想想的地方,你現在完成一個很複雜的操作,其中不但包含一個座標或者是一堆座標,也或者包含了很多的顏色變化,此時你使用屬性動畫就不是一個明智的選擇了;爲什麼呢?你想想你要完成我所說的需要創建多少個屬性動畫類?很多吧~浪費內存CPU吧?你敢說沒有???

既然今天是說優化,那就來優化優化~~

優化

針對上面的情況我們有兩種解決方案

第一種

使用一個 Animation ,然後在 protected void applyTransformation(float interpolatedTime, Transformation t)中回調處理具體的情況;具體可以看看我的文章:打造極致Material Design動畫風格Button 中有一定的介紹,其效率遠遠要高於上面的多個屬性動畫的情況。

第二種

第一種是採用最基本的 Animation 來實現的,這第二種也是使用屬性動畫。

先看看一部分代碼:

   public static class ViewProperty {
        private float paintX = 0;
        private float paintY = 0;

        public ViewProperty() {
        }

        public ViewProperty(float paintX, float paintY) {
            this.paintX = paintX;
            this.paintY = paintY;
        }
    }

是的我們使用一個內部類把所有的屬性進行一次封裝;然後就可以只使用一個屬性動畫了;現在看看代碼:

   private ViewProperty mProperty = new ViewProperty(0, 0);
    private Property<MyView, ViewProperty> PaintProperty = new Property<MyView, ViewProperty>(ViewProperty.class, "paintX") {
        @Override
        public ViewProperty get(MyView object) {
            return object.mProperty;
        }

        @Override
        public void set(MyView object, ViewProperty value) {
            object.mProperty = value;
        }
    };

    private void start() {
        //Paint
        ObjectAnimator aPaint = ObjectAnimator.ofObject(this, PaintProperty, new ViewProperty(0, 0), new ViewProperty(100, 100));
        aPaint.start();
    }

是不是很簡單?是不是隻有一個屬性動畫:ObjectAnimator ,是的 ~是的 ! 

別高興的太早了~~看看實際情況:


擦~~~這個是怎麼了??哪裏出錯了??

思考

我們應該想想,我們的想法是好的,封裝一個屬性集合類的實例,然後就可以只使用一個屬性動畫了;但是問題出在哪裏呢?

我們想想,對於Float,Int這些而言,在更改的時候都是採用 C=A+(B-A)*T 這樣的情況來的,但是對於Object類型來說呢?這個它怎麼減去,怎麼運算?

我想這是應該我們去實現的地方,我們需要告訴程序按照什麼樣的方式去運算: C=A+(B-A)*T 這樣的一個公式,告訴它在時間等值情況下進行了10%的時間的時候應該是:new ViewProperty(10, 10),這個值!

TypeEvaluator

public interface TypeEvaluator<T> {

    /**
     * This function returns the result of linearly interpolating the start and end values, with
     * <code>fraction</code> representing the proportion between the start and end values. The
     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
     * and <code>t</code> is <code>fraction</code>.
     *
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start value.
     * @param endValue   The end value.
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public T evaluate(float fraction, T startValue, T endValue);

}
在動畫類中,有這樣的一個接口,這個接口所完成的工作就是上面的: C=A+(B-A)*T 

其是我們可以看看:

    public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
            TypeEvaluator<V> evaluator, V... values) {
        ObjectAnimator anim = new ObjectAnimator(target, property);
        anim.setObjectValues(values);
        anim.setEvaluator(evaluator);
        return anim;
    }
在屬性動畫 ObjectAnimator 類的實例化中有這樣的一個構造函數,在該構造函數中就允許用戶自己指定自己的運算接口類。

現在我們繼承該接口,並實現它:

PaintEvaluator

    public static class PaintEvaluator implements TypeEvaluator {
        private static final PaintEvaluator sInstance = new PaintEvaluator();

        public static PaintEvaluator getInstance() {
            return sInstance;
        }

        public Object evaluate(float fraction, Object startValue, Object endValue) {
            ViewProperty start = (ViewProperty) startValue;
            ViewProperty end = (ViewProperty) endValue;

            float x = start.paintX + fraction * (end.paintX - start.paintX);
            float y = start.paintY + fraction * (end.paintY - start.paintY);

            return new ViewProperty(x, y);
        }
    }
很簡單吧。就是分別計算x,y;然後返回一個類的實例就OK了。

結束

然後修改上面的啓動代碼爲:

    private ViewProperty mProperty = new ViewProperty(0, 0);
    private static PaintEvaluator PAINTEVALUATOR = new PaintEvaluator();
    private static Property<MyView, ViewProperty> PaintProperty = new Property<MyView, ViewProperty>(ViewProperty.class, "paint") {
        @Override
        public ViewProperty get(MyView object) {
            return object.mProperty;
        }

        @Override
        public void set(MyView object, ViewProperty value) {
            object.mProperty = value;
        }
    };

    private void start() {
        //Paint
        ObjectAnimator paint = ObjectAnimator.ofObject(this, PaintProperty, PAINTEVALUATOR, new ViewProperty(0, 0), new ViewProperty(100, 100));
        paint.start();
    }
OK,大功告成~~
現在纔是夠簡單,夠舒爽~~

祝,大家都能寫出稱心如意的代碼~~

========================================================
作者:qiujuer
博客:blog.csdn.net/qiujuer
網站:www.qiujuer.net
開源庫:Genius-Android
轉載請註明出處:http://blog.csdn.net/qiujuer/article/details/42531485

——學之開源,用於開源;初學者的心態,與君共勉!
========================================================

發佈了82 篇原創文章 · 獲贊 709 · 訪問量 66萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章