Android属性动画ObjectAnimator源码简单分析

在前一篇文章Android属性动画ValueAnimator源码简单分析的基础之上。继续看ObjectAnimator里面的简单实现。

前一篇文章Android属性动画ValueAnimator源码简单分析非常非常简单的分析了Android属性动画ValueAnimator源码,做一个简单的总结,简单来说ValueAnimator里面做的事情就是先通过ValueAnimator.ofInt()或者ValueAnimator.ofArgb()或者ValueAnimator.ofFloat()等函数去生成一个PropertyValuesHolder对象,把整个动画过程中的关键时间点先拆分好放在一个Keyframe对象的List里面,通过PropertyValuesHolder去关联这些Keyframe List,之后调用了ValueAnimator.start()函数之后,在动画的播放过程中通过PropertyValuesHolder对象的calculateValue函数根据传入的时间点去获取属性的值,然后调用AnimatorUpdateListener接口的onAnimationUpdate()回调函数告诉上层动画播放过程中值得变化。所以在使用ValueAnimator的时候我们要自己去实现AnimatorUpdateListener(onAnimationUpdate)的回调接口。

ObjectAnimator是ValueAnimator的子类,他对ValueAnimator做了进一步的封装,他要比ValueAnimator多一步在动画的播放过程中通过PropertyValuesHolder对象的calculateValue函数根据传入的时间点去获取属性的值之后,他会帮忙多做一些处理。调用target对象protertyName属性的set方法。为了了解ObjectAnimator类大概的实现过程,接下来就在前一篇文章Android属性动画ValueAnimator源码简单分析基础上继续看看ObjectAnimator源码的简单实现。

ObjectAnimator的简单实用,如下

        ObjectAnimator objectAlpha = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f, 1f);
        objectAlpha.setDuration(3000);
        objectAlpha.start();

为了分析ObjectAnimator源码的简单实现,还是按照我们的使用过程分三部分来看
1. ObjectAnimator.ofFloat(this, “alpha”, 1f, 0f, 1f);这里干了些啥。
2. objectAlpha.start();里面都干了些啥子东西。
3. 动画过程中PropertyValuesHolder对象的calculateValue函数之后干了什么事情。

第一部分ObjectAnimator.ofFloat(this, “alpha”, 1f, 0f, 1f)

    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }

就三行代码,先看第二行这个和我们在Android属性动画ValueAnimator源码简单分析里面分析ValueAnimator.ofInt()的时候过程是一样的,那只需要看下第一行代码干了什么。

    private ObjectAnimator(Object target, String propertyName) {
        setTarget(target);
        setPropertyName(propertyName);
    }

设置target和属性的名字(propertyName)。target是不能为null的,target就是属性名对应的对象。在后面会调用target对应的属性名字的get 和 set函数。

恩,第一部分好像就完了,和ValueAnimator的不同点就是多了target和propertyName。其他的过程都是和 分析ValueAnimator.ofInt()的时候过程是一样的。

第二部分objectAlpha.start();里面都干了些啥子东西

    @Override
    public void start() {
        // See if any of the current active/pending animators need to be canceled
        AnimationHandler handler = sAnimationHandler.get();
        if (handler != null) {
            int numAnims = handler.mAnimations.size();
            for (int i = numAnims - 1; i >= 0; i--) {
                if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
                    ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                        anim.cancel();
                    }
                }
            }
            numAnims = handler.mPendingAnimations.size();
            for (int i = numAnims - 1; i >= 0; i--) {
                if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
                    ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                        anim.cancel();
                    }
                }
            }
            numAnims = handler.mDelayedAnims.size();
            for (int i = numAnims - 1; i >= 0; i--) {
                if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
                    ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                        anim.cancel();
                    }
                }
            }
        }
        if (DBG) {
            Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
            for (int i = 0; i < mValues.length; ++i) {
                PropertyValuesHolder pvh = mValues[i];
                Log.d(LOG_TAG, "   Values[" + i + "]: " +
                    pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
                    pvh.mKeyframes.getValue(1));
            }
        }
        super.start();
    }

有了文章ValueAnimator.start()的过程分析,我们知道第4行handler = sAnimationHandler.get();得到的handler里面有好多List,什么pending动画的List啊,什么delay动画的List啊,什么read动画的List啊。
7-14行,如果要启动的ObjectAnimator 存在于 mAnimations的List中,把这个动画cancel掉。
15-23行,如果要启动的ObjectAnimator 存在于 mPendingAnimations的List中,把这个动画cancel掉。
24-32行,如果要启动的ObjectAnimator 存在于 mDelayedAnims的List中,把这个动画cancel掉。
34-42行,DBG这个就不管了。
43行,调用了super的start()函数了,就是ValueAnimator.start()。前一篇文章Android属性动画ValueAnimator源码简单分析ValueAnimator.start()分析是一样的了。

恩,第二部分也结束了,就是正常的去启动动画,如果之前这个动画存在就cancel掉。好像也没什么特别的在里面。

第三部动画过程中PropertyValuesHolder对象的calculateValue函数之后干了什么事情。

有了Android属性动画ValueAnimator源码简单分析的基础,知道动画播放的过程中会走到ValueAnimator类中的animateValue()函数。在分析ObjectAnimator的时候我们就得看ObjectAnimator的animateValue()函数了,没什么说的跟进去。
ObjectAnimator类的animateValue()函数的源码如下

    @CallSuper
    @Override
    void animateValue(float fraction) {
        final Object target = getTarget();
        if (mTarget != null && target == null) {
            // We lost the target reference, cancel and clean up.
            cancel();
            return;
        }

        super.animateValue(fraction);
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].setAnimatedValue(target);
        }
    }

5-9行,当我们在前面设置了target的对象,但是这个对象在外面被释放掉了才会进入这个if,把这个动画cancel掉,这个好好理解吧 target都没有了。这个动画也就没意义了。这里使用了弱应用,也是为了避免内存泄露。
11行,调用super的animaterValue函数,直接进入到了ValueAnimator类中的animaterValue函数了。Android属性动画ValueAnimator源码简单分析分析过。
14行,mValues[i].setAnimatedValue(target); ObjectAnimator动画的重点来了。Android属性动画ValueAnimator源码简单分析的分析 mValues就是PropertyValuesHolder的对象或者他的子类对象,接着跟进去PropertyValuesHolder类中的setAnimatedValue函数。

    void setAnimatedValue(Object target) {
        if (mProperty != null) {
            mProperty.set(target, getAnimatedValue());
        }
        if (mSetter != null) {
            try {
                mTmpValueArray[0] = getAnimatedValue();
                mSetter.invoke(target, mTmpValueArray);
            } catch (InvocationTargetException e) {
                Log.e("PropertyValuesHolder", e.toString());
            } catch (IllegalAccessException e) {
                Log.e("PropertyValuesHolder", e.toString());
            }
        }
    }

第7行,mTmpValueArray[0] = getAnimatedValue();得到的就是这个时候动画的值。
第8行,这行代码底下做的事情就是根据我们前面设置的target和propertyName。掉用了target对象对应propertyName的set方法,同时对应的参数就是动画过程中的值。

这里出现了mSetter。接下来就得简单看下这个是怎么得到了,他是怎么把target和propertyName对应的set方法关联起来的了。先看
ObjectAnimator类的initAnimation函数,这个函数的调用时机Android属性动画ValueAnimator源码简单分析有分析到

    @CallSuper
    @Override
    void initAnimation() {
        if (!mInitialized) {
            // mValueType may change due to setter/getter setup; do this before calling super.init(),
            // which uses mValueType to set up the default type evaluator.
            final Object target = getTarget();
            if (target != null) {
                final int numValues = mValues.length;
                for (int i = 0; i < numValues; ++i) {
                    mValues[i].setupSetterAndGetter(target);
                }
            }
            super.initAnimation();
        }
    }

直接跳到11行,调用了PropertyValuesHolder类的setupSetterAndGetter方法。

    void setupSetterAndGetter(Object target) {
        mKeyframes.invalidateCache();
        if (mProperty != null) {
            // check to make sure that mProperty is on the class of target
            try {
                Object testValue = null;
                List<Keyframe> keyframes = mKeyframes.getKeyframes();
                int keyframeCount = keyframes == null ? 0 : keyframes.size();
                for (int i = 0; i < keyframeCount; i++) {
                    Keyframe kf = keyframes.get(i);
                    if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                        if (testValue == null) {
                            testValue = convertBack(mProperty.get(target));
                        }
                        kf.setValue(testValue);
                        kf.setValueWasSetOnStart(true);
                    }
                }
                return;
            } catch (ClassCastException e) {
                Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +
                        ") on target object " + target + ". Trying reflection instead");
                mProperty = null;
            }
        }
        // We can't just say 'else' here because the catch statement sets mProperty to null.
        if (mProperty == null) {
            Class targetClass = target.getClass();
            if (mSetter == null) {
                setupSetter(targetClass);
            }
            List<Keyframe> keyframes = mKeyframes.getKeyframes();
            int keyframeCount = keyframes == null ? 0 : keyframes.size();
            for (int i = 0; i < keyframeCount; i++) {
                Keyframe kf = keyframes.get(i);
                if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                    if (mGetter == null) {
                        setupGetter(targetClass);
                        if (mGetter == null) {
                            // Already logged the error - just return to avoid NPE
                            return;
                        }
                    }
                    try {
                        Object value = convertBack(mGetter.invoke(target));
                        kf.setValue(value);
                        kf.setValueWasSetOnStart(true);
                    } catch (InvocationTargetException e) {
                        Log.e("PropertyValuesHolder", e.toString());
                    } catch (IllegalAccessException e) {
                        Log.e("PropertyValuesHolder", e.toString());
                    }
                }
            }
        }
    }

直接跳到29-31行,注意这里mSetter出现了哦。最初的时候应该是空的走setupSetter(targetClass);方法。参数就是target的class。

    void setupSetter(Class targetClass) {
        Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
    }

第3行 调用了setupSetterOrGetter函数得到了mSetter对象,看到参数里面有set字符的关键字。

    private Method setupSetterOrGetter(Class targetClass,
            HashMap<Class, HashMap<String, Method>> propertyMapMap,
            String prefix, Class valueType) {
        Method setterOrGetter = null;
        synchronized(propertyMapMap) {
            // Have to lock property map prior to reading it, to guard against
            // another thread putting something in there after we've checked it
            // but before we've added an entry to it
            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
            boolean wasInMap = false;
            if (propertyMap != null) {
                wasInMap = propertyMap.containsKey(mPropertyName);
                if (wasInMap) {
                    setterOrGetter = propertyMap.get(mPropertyName);
                }
            }
            if (!wasInMap) {
                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
                if (propertyMap == null) {
                    propertyMap = new HashMap<String, Method>();
                    propertyMapMap.put(targetClass, propertyMap);
                }
                propertyMap.put(mPropertyName, setterOrGetter);
            }
        }
        return setterOrGetter;
    }

直接跳到9行,getPropertyFunction方法

    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
        // TODO: faster implementation...
        Method returnVal = null;
        String methodName = getMethodName(prefix, mPropertyName);
        Class args[] = null;
        if (valueType == null) {
            try {
                returnVal = targetClass.getMethod(methodName, args);
            } catch (NoSuchMethodException e) {
                // Swallow the error, log it later
            }
        } else {
            args = new Class[1];
            Class typeVariants[];
            if (valueType.equals(Float.class)) {
                typeVariants = FLOAT_VARIANTS;
            } else if (valueType.equals(Integer.class)) {
                typeVariants = INTEGER_VARIANTS;
            } else if (valueType.equals(Double.class)) {
                typeVariants = DOUBLE_VARIANTS;
            } else {
                typeVariants = new Class[1];
                typeVariants[0] = valueType;
            }
            for (Class typeVariant : typeVariants) {
                args[0] = typeVariant;
                try {
                    returnVal = targetClass.getMethod(methodName, args);
                    if (mConverter == null) {
                        // change the value type to suit
                        mValueType = typeVariant;
                    }
                    return returnVal;
                } catch (NoSuchMethodException e) {
                    // Swallow the error and keep trying other variants
                }
            }
            // If we got here, then no appropriate function was found
        }

        if (returnVal == null) {
            Log.w("PropertyValuesHolder", "Method " +
                    getMethodName(prefix, mPropertyName) + "() with type " + valueType +
                    " not found on target class " + targetClass);
        }

        return returnVal;
    }

看到有mPropertyName,其实他就是我们ObjectAnimator.ofFloat(this, “alpha”, 1f, 0f, 1f)时候传递进来的alpha。
第4行,returnVal = targetClass.getMethod(methodName, args); 估计得到的就是 setAlpha的方法。
到此我们就知道了mSetter对象是在哪里得到了,在具体的就不进去看了。

总结第三部的分析就是在动画过程中得到了动画变化的值之后,通过调用相应的setXXX的方法把这个值给设置进去。所以在用ObjectAnimator动画的时候,一定要实现对应的set get方法。

流水账有记完了,下一篇准备看看AnimatorSet里面大概的实现。Android属性动画AnimatorSet源码简单分析

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值