Android 属性动画代码分析(基于ObjectAnimator)

android属性动画是开发中经常使用的一项技能,但是我之前却从没有深究过动画实现原理,本文基于android 8.0,撸了一把ObjectAnimator源码,分析属性动画执行关键的过程。

一、动画执行的两个主要的问题

  1. 动画每一帧执行的信号是如何产生的:是handler循环还是。。。?
  2. View的属性是怎么产生变化的:在每一帧循环中,view的属性是怎么样被改变的

二、带着上述的两个问题,以alpha属性动画为例,分析ObjectAnimator的初始化

基本使用:

ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1, 0);
alpha.setDuration(1000);
alpha.start();

1.跟进ofFloat方法:执行了首先new ObjectAnimator()的操作,设置view和属性名

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

然后执行了一个比较重要的初始化方法:setFloatValues(),这里将初始化帧序列

  @Override
    public void setFloatValues(float... values) {
        if (mValues == null || mValues.length == 0) {          
            if (mProperty != null) {
                setValues(PropertyValuesHolder.ofFloat(mProperty, values));
            } else {
                //从这个入口继续往下,因为我们传入的是一个属性名,是一个字符串
                setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
            }
        } else {
            super.setFloatValues(values);
        }
    }

2.执行PropertyValuesHolder.ofFloat()方法,进入PropertyValuesHolder类中,初始化的是PropertyValuesHolder的子类:FloatPropertyValuesHolder,然后执行了FloatPropertyValuesHolder类中的setFloatValues()方法,最终执行父类PropertyValuesHolder的setFloatValues()方法。

//父类的setFloatValues方法,调用KeyframeSet.ofFloat方法初始化mKeyframes
public void setFloatValues(float... values) {
        mValueType = float.class;
        mKeyframes = KeyframeSet.ofFloat(values);
    }
//子类FloatPropertyValuesHolder的方法,调用了父类的setFloatValues(),并将mKeyframes强转成FloatKeyframes类型对象
@Override
public void setFloatValues(float... values) {
        super.setFloatValues(values);
        mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
    }

3.跟进KeyframeSet.ofFloat(values)方法

 public static KeyframeSet ofFloat(float... values) {
        boolean badValue = false;
        int numKeyframes = values.length;
        //初始化一个FloatKeyframe 类型数组
        FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
        //只有一帧时(参数里只有一个value),初始帧默认为0和结束帧设为该value
        if (numKeyframes == 1) {
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
            keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
            if (Float.isNaN(values[0])) {
                badValue = true;
            }
        } else {
            //初始化第一个帧
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
            for (int i = 1; i < numKeyframes; ++i) {
            //这里比较重要:将每一个value值封装成一个FloatKeyframe(一个动画帧),第一个参数是当前value参数的下标与总value参数个数的比值,这个值会在后面用来分配每两个帧之间的动画时间,第二个参数为我们传入的value值
                keyframes[i] =
                        (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
                if (Float.isNaN(values[i])) {
                    badValue = true;
                }
            }
        }
        if (badValue) {
            Log.w("Animator", "Bad value (NaN) in float animator");
        }
        //将keyframes数组封装成FloatKeyframeSet并返回FloatKeyframeSet对象,即在FloatKeyframeSet保存了帧序列的数组
        return new FloatKeyframeSet(keyframes);
    }

在FloatKeyframe中只是简单保存了我们传入的参数

 FloatKeyframe(float fraction, float value) {
            //下标比值
            mFraction = fraction;
            //在上面的Keyframe.ofFloat()中传入的value值
            mValue = value;
            mValueType = float.class;
            mHasValue = true;
        }

4.总结一下ObjectAnimator.ofFloat()这个方法主要干了什么:分别将view和mPropertyName属性值用target变量、mPropertyName变量保存;setFloatValues()方法中初始化一些帧序列,即:我们传入的每一个value值会用FloatKeyframe对象封装成一个序列帧(Keyframe.ofFloat()方法),多个序列帧对象封装成FloatKeyframeSet对象,该对象是封装了多个序列帧的集合,该帧集合对象在PropertyValuesHolder对象的setFloatValues()方法中被返回,并保存在mKeyframes变量里面;

三、start()方法开启动画分析
直接进入ValueAnimator的start()方法中,playBackwards:是否逆序播放,传入的是false,我们跳过函数前面的一些判断初始化部分,看到addAnimationCallback函数

private void start(boolean playBackwards) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        mReversing = playBackwards;
        mSelfPulse = !mSuppressSelfPulseRequested;
        // Special case: reversing from seek-to-0 should act as if not seeked at all.
        if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
            if (mRepeatCount == INFINITE) {
                // Calculate the fraction of the current iteration.
                float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
                mSeekFraction = 1 - fraction;
            } else {
                mSeekFraction = 1 + mRepeatCount - mSeekFraction;
            }
        }
        mStarted = true;
        mPaused = false;
        mRunning = false;
        mAnimationEndRequested = false;
        // Resets mLastFrameTime when start() is called, so that if the animation was running,
        // calling start() would put the animation in the
        // started-but-not-yet-reached-the-first-frame phase.
        mLastFrameTime = -1;
        mFirstFrameTime = -1;
        mStartTime = -1;
        //这里函数将添加回调,即解决文章开始提出的第一个问题:动画每一帧的回调的信号是怎么产生的
        addAnimationCallback(0);

        if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
            //开始动画的一些初始化
            startAnimation();
            if (mSeekFraction == -1) {               
                setCurrentPlayTime(0);
            } else {
                setCurrentFraction(mSeekFraction);
            }
        }
    }

下面我们主要分析start()方法中的addAnimationCallback()、startAnimation()和setCurrentFraction()方法,在这几个方法中解决了我们最开始的两个问题
1.动画引擎:addAnimationCallback(),动画怎么获得信号然后刷新的,将在这里看见,该函数调用了AnimationHandler类的addAnimationFrameCallback()方法

//FrameCallback:信号首先在这个回调里接收
 private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            //调用doAnimationFrame()具体执行动画刷新任务,进而调用ValueAnimatord的doAnimationFrame()方法,并传入一个时间戳
            doAnimationFrame(getProvider().getFrameTime());
            //mAnimationCallbacks保存每一个要接收信号的ValueAnimator实例
            if (mAnimationCallbacks.size() > 0) {
                //因为AnimationHandler是线程私有且单例,当还有动画在执行(即mAnimationCallbacks不空),就要接收下一次的刷新信号,每次都接收信号就类似一个Timer定时器
                getProvider().postFrameCallback(this);
            }
        }
    };
    /**
     * Register to get a callback on the next frame after the delay.
     */
    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        if (mAnimationCallbacks.size() == 0) {
            //getProvider()获得MyFrameCallbackProvider实例
            getProvider().postFrameCallback(mFrameCallback);
        }
        //加入到列表,回调的时候要遍历这个列表
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }

        if (delay > 0) {
            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
        }
    }
     /**
     * Default provider of timing pulse that uses Choreographer for frame callbacks.
     */
    private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {

        final Choreographer mChoreographer = Choreographer.getInstance();

        @Override
        public void postFrameCallback(Choreographer.FrameCallback callback) {
            //Choreographer 是接收底层VSync信号刷新屏幕信号的一个类,当将callback加入,意味着在下一次刷新信号到来时要回调该callback,
            //即形成了信号源,给了动画刷新以时机。在ViewRootImpl有着类似的操作,也是通过post这样一个回调完成整个UI的绘制,理论上是16ms回调一次
            mChoreographer.postFrameCallback(callback);
        }

        @Override
        public void postCommitCallback(Runnable runnable) {
            mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
        }

        @Override
        public long getFrameTime() {
            return mChoreographer.getFrameTime();
        }

        @Override
        public long getFrameDelay() {
            return Choreographer.getFrameDelay();
        }

        @Override
        public void setFrameDelay(long delay) {
            Choreographer.setFrameDelay(delay);
        }
    }

2.刷新机制清楚了,那么是怎么让view动起来的呢?直接进入startAnimation()->initAnimation()方法。
①在ObjectAnimator调用了setupSetterAndGetter()和父类的initAnimation()方法

  @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;
                //还记得mValues是什么吗,这是在初始化ObjectAnimator的时候,setFloatValues()方法中设置的,是一个FloatPropertyValuesHolder对象,保存了帧序列集合
                for (int i = 0; i < numValues; ++i) {
                    //target是最初初始化ObjectAnimator的时候传入的View对象
                    mValues[i].setupSetterAndGetter(target);
                }
            }
            super.initAnimation();
        }
    }

②我们进入到setupSetterAndGetter()方法,这里mSetter = null,主要调用setupSetter()方法为mSetter 赋值,在setupSetter方法中调用了setupSetterOrGetter()方法,传入的参数是view.class对象,下面看一下这个方法干了什么

void setupSetterAndGetter(Object target) {
        //删除mProperty!=null的情况的代码,因为我们传入的是一个属性值
        if (mProperty == null) {
            Class targetClass = target.getClass();
            if (mSetter == null) {
                //初始化mSetter,mSetter保存了view的一个Method对象
                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());
                    }
                }
            }
        }
    }

③setupSetterOrGetter()方法干了什么:

//propertyMapMap是全局的static final的map对象(类型是HashMap<Class, HashMap<String, Method>>),
//view.class为key,value也是一个hashmap,用来保存属性名和其对应的Method对象
private Method setupSetterOrGetter(Class targetClass,
            HashMap<Class, HashMap<String, Method>> propertyMapMap,
            String prefix, Class valueType) {
        Method setterOrGetter = null;
        synchronized(propertyMapMap) {
            //先在全局map中以view.class为key查找
            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
            boolean wasInMap = false;
            //找到了直接返回
            if (propertyMap != null) {
                wasInMap = propertyMap.containsKey(mPropertyName);
                if (wasInMap) {
                    setterOrGetter = propertyMap.get(mPropertyName);
                }
            }
            //没找到,要新建,进入了getPropertyFunction()方法,传入参数为view.class,prefix为字符串"set",valueType方法参数,float.class
            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;
    }
//这个方法是根据属性名和前缀("set"),以反射的方式拿到View的对应的Method
private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
        Method returnVal = null;
        //根据属性名和前缀("set")拼接方法名,比如我们传入的属性值是"alpha",则这里返回setAlpha,
        //这里就看到了我们初始化ObjectAnimator时传入的第二个参数"alpha"的作用了,就是为了反射拿到该对象的方法
        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;
    }

④总结一下initAnimation()主要作用:反射拿到动画执行过程中需要调用的view对应的方法,这里是setAlpha。
3.setCurrentFraction()->animateValue(),该方法调用了calculateValue(),该函数我们结合doAnimationFrame()函数说明(该函数是在ValueAnimator中回调的,在刷新机制介绍过),
①doAnimationFrame()函数

//每次刷新都会回调的方法,回调函数中除了一些必要的错误处理和判断,最重要的是animateBasedOnTime()函数
public final boolean doAnimationFrame(long frameTime) {
        if (mStartTime < 0) {
            mStartTime = mReversing ? frameTime : frameTime + (long) (mStartDelay * sDurationScale);
        }

        // Handle pause/resume
        if (mPaused) {
            mPauseTime = frameTime;
            removeAnimationCallback();
            return false;
        } else if (mResumed) {
            mResumed = false;
            if (mPauseTime > 0) {
                // Offset by the duration that the animation was paused
                mStartTime += (frameTime - mPauseTime);
            }
        }

        if (!mRunning) {
            if (mStartTime > frameTime && mSeekFraction == -1) {
                return false;
            } else {
                mRunning = true;
                startAnimation();
            }
        }

        if (mLastFrameTime < 0) {
            if (mSeekFraction >= 0) {
                long seekTime = (long) (getScaledDuration() * mSeekFraction);
                mStartTime = frameTime - seekTime;
                mSeekFraction = -1;
            }
            mStartTimeCommitted = false; // allow start time to be compensated for jank
        }
        mLastFrameTime = frameTime;
        //防止回调时间比动画开始时间还要早
        final long currentTime = Math.max(frameTime, mStartTime);
        boolean finished = animateBasedOnTime(currentTime);

        if (finished) {
            endAnimation();
        }
        return finished;
    }
    boolean animateBasedOnTime(long currentTime) {
        boolean done = false;
        if (mRunning) {
            //获取设置的动画时长
            final long scaledDuration = getScaledDuration();
            //比例值:当前动画进行的时间除以动画总时长得到动画进行的比率
            final float fraction = scaledDuration > 0 ?
                    (float)(currentTime - mStartTime) / scaledDuration : 1f;
            final float lastFraction = mOverallFraction;
            final boolean newIteration = (int) fraction > (int) lastFraction;
            final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
                    (mRepeatCount != INFINITE);
            if (scaledDuration == 0) {
                // 0 duration animator, ignore the repeat count and skip to the end
                done = true;
            } else if (newIteration && !lastIterationFinished) {
                // Time to repeat
                if (mListeners != null) {
                    int numListeners = mListeners.size();
                    for (int i = 0; i < numListeners; ++i) {
                        mListeners.get(i).onAnimationRepeat(this);
                    }
                }
            } else if (lastIterationFinished) {
                done = true;
            }
            mOverallFraction = clampFraction(fraction);
            //这里对比率做一些处理,因为存在循环动画(重复多次),计算出来的就是每一次动画进行的比率值(动画进度)
            float currentIterationFraction = getCurrentIterationFraction(
                    mOverallFraction, mReversing);
            //这里也调用了该函数,可见这是让View动起来的关键
            animateValue(currentIterationFraction);
        }
        return done;
    }

②动起来的关键:animateValue()函数,该函数传入了一个动画执行比率值,描述动画执行进度,父类的该函数又调用了PropertyValuesHolder对象的一个calculateValue()函数,然后调用setAnimatedValue()函数

      @CallSuper
      @Override
      void animateValue(float fraction) {
        final Object target = getTarget();
        if (mTarget != null && target == null) {
            // We lost the target reference, cancel and clean up. Note: we allow null target if the
            /// target has never been set.
            cancel();
            return;
        }
        super.animateValue(fraction);
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            //将计算后的属性值赋值给我们需要动画的view
            mValues[i].setAnimatedValue(target);
        }
    }
    //父类的animateValue方法
     @CallSuper
    void animateValue(float fraction) {
        //根据自定义的插值器,动态修改动画的执行进度,可以使动画执行的更丰富
        fraction = mInterpolator.getInterpolation(fraction);
        mCurrentFraction = fraction;
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            //根据当前时间进度计算属性值
            mValues[i].calculateValue(fraction);
        }
        if (mUpdateListeners != null) {
            int numListeners = mUpdateListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                mUpdateListeners.get(i).onAnimationUpdate(this);
            }
        }
    }

    //我们看一下calculateValue()是做了什么操作,调用了初始化阶段定义的帧序列集合(mFloatKeyframes是FloatKeyframeSet实例)的getFloatValue方法,最终会调用FloatKeyframeSet的getFloatValue方法
        @Override
        void calculateValue(float fraction) {
            mFloatAnimatedValue = mFloatKeyframes.getFloatValue(fraction);
        }

③getFloatValue(float fraction)方法,参数也是动画执行进度值,这个函数用来根据这个线性的时间进度计算属性值

    @Override
    public float getFloatValue(float fraction) {
        //动画最开始
        if (fraction <= 0f) {
            final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
            final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
            float prevValue = prevKeyframe.getFloatValue();
            float nextValue = nextKeyframe.getFloatValue();
            float prevFraction = prevKeyframe.getFraction();
            float nextFraction = nextKeyframe.getFraction();
            final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
            if (interpolator != null) {
                fraction = interpolator.getInterpolation(fraction);
            }
            float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
            return mEvaluator == null ?
                    prevValue + intervalFraction * (nextValue - prevValue) :
                    ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
                            floatValue();                          
        } else if (fraction >= 1f) {
            //最后结束
            final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
            final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
            float prevValue = prevKeyframe.getFloatValue();
            float nextValue = nextKeyframe.getFloatValue();
            float prevFraction = prevKeyframe.getFraction();
            float nextFraction = nextKeyframe.getFraction();
            final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
            if (interpolator != null) {
                fraction = interpolator.getInterpolation(fraction);
            }
            float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
            return mEvaluator == null ?
                    prevValue + intervalFraction * (nextValue - prevValue) :
                    ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
                            floatValue();
        }
        //我们主要看一下这里,上面两种情况类似
        //拿到第一帧,再次说明,这些帧序列是初始化动画时根据每一个value封装起来的。
        FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
        //getFraction()拿的是什么:初始化帧序列的时候放的一个参数,该参数描述该帧的下标对总帧数的比值,
        //比如一共10帧(传入了10个value),第一帧是0,第二帧为1/9,第三帧为2/9,以此类推,参考帧初始化那里
        //循环的作用:遍历拿到这样的两帧:刚好前一帧的getFraction()小于fraction且后一帧的大于fraction
        for (int i = 1; i < mNumKeyframes; ++i) {
            FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
            if (fraction < nextKeyframe.getFraction()) {
                final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
                //根据fraction 获取一个相对比值,
                float intervalFraction = (fraction - prevKeyframe.getFraction()) /
                    (nextKeyframe.getFraction() - prevKeyframe.getFraction());
                float prevValue = prevKeyframe.getFloatValue();
                float nextValue = nextKeyframe.getFloatValue();
                // Apply interpolator on the proportional duration.
                //获取动画插值器返回的值,插值器可以动态改变动画执行进度速率等,这里为null(没看到有初始化这东西的地方,自定义差值器被使用是在ValueAnimator中的)
                if (interpolator != null) {
                    intervalFraction = interpolator.getInterpolation(intervalFraction);
                }
                //mEvaluator是可以自定义的,可以实现更丰富的动画,可以自行百度
                //从该公式的计算可以看出,每两个value之间的时间片是均匀的(线性插值器情况下),即每两个value之间的变换时间是一样的
                return mEvaluator == null ?
                        prevValue + intervalFraction * (nextValue - prevValue) :
                        ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
                            floatValue();
            }
            prevKeyframe = nextKeyframe;
        }
        // shouldn't get here
        return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
    }

④最后一步:setAnimatedValue(),将计算的属性赋值给view,还记得我们之前反射拿到的Method方法吗,这个Method就是mSetter,这个方法只是简单的反射执行动画而已,现在知道了view是怎么动起来的了。
如果需要自定义高级动画,例如:在自定义view中定义一个方法为setXxxx(Object object),我们就可以将”alpha”替换成”xxxx”,参数Object也可以自定义,使用ObjectAnimator.ofObject(),其中一个参数为TypeEvaluator 类型,具体可以参考setEvaluator(TypeEvaluator value)这个方法的使用,计算和之前alpha动画类似,在KeyframeSet类的getValue(float fraction)方法中,将在自定义的TypeEvaluator计算之后,反射调用setXxxx方法。

        @Override
        void setAnimatedValue(Object target) {
            if (mFloatProperty != null) {
                mFloatProperty.setValue(target, mFloatAnimatedValue);
                return;
            }
            if (mProperty != null) {
                mProperty.set(target, mFloatAnimatedValue);
                return;
            }
            if (mJniSetter != 0) {
                nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
                return;
            }
            if (mSetter != null) {
                try {
                    //mFloatAnimatedValue 就是前面计算出的属性值
                    mTmpValueArray[0] = mFloatAnimatedValue;
                     //反射执行动画,即调用了view.setAlpha(mTmpValueArray)方法,刷新动画,到此,整个动画执行流程完成
                    mSetter.invoke(target, mTmpValueArray);
                } catch (InvocationTargetException e) {
                    Log.e("PropertyValuesHolder", e.toString());
                } catch (IllegalAccessException e) {
                    Log.e("PropertyValuesHolder", e.toString());
                }
            }
        }

猜你喜欢

转载自blog.csdn.net/weixin_38062353/article/details/81585300