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

——学之开源,用于开源;初学者的心态,与君共勉!
========================================================

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。