属性动画源码分析

作者: nothingwxq | 来源:发表于2017-07-14 13:12 被阅读113次

    分析版本api 24

    首先我们要找一个入口,就从ObjectAnimator.ofInt(this, "width", 0, -20).start()开始吧,其他动画都是类似的。

    先看参数构造

    ObjectAnimator.ofInt(this, "currentProgress", 0, progress)

       / *
         * @param target The object whose property is to be animated.
         * @param property The property being animated.
         * @param values A set of values that the animation will animate between over time.
         * @return An ObjectAnimator object that is set up to animate between the given values.
         */
        public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
            ObjectAnimator anim = new ObjectAnimator(target, property);
            anim.setIntValues(values);
            return anim;
        }
    

    通过target, property构造了ObjectAnimator,并设置了可变int数组values ,继续看 anim.setIntValues(values);

     @Override
        public void setIntValues(int... values) {
            if (mValues == null || mValues.length == 0) {
                // No values yet - this animator is being constructed piecemeal. Init the values with
                // whatever the current propertyName is
                if (mProperty != null) {
                    setValues(PropertyValuesHolder.ofInt(mProperty, values));
                } else {
                    setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
                }
            } else {
                super.setIntValues(values);
            }
        }
    

    a 继续数组为空时,调用自身的setIntValues(values),

       public void setValues(PropertyValuesHolder... values) {
            int numValues = values.length;
            mValues = values;
            mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
            for (int i = 0; i < numValues; ++i) {
                PropertyValuesHolder valuesHolder = values[i];
                mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
            }
            // New property/values/target should cause re-initialization prior to starting
            mInitialized = false;
        }
    

    b 否则父类的ValueAnimator的public void setValues(PropertyValuesHolder... values)

      public void setIntValues(int... values) {
            if (values == null || values.length == 0) {
                return;
            }
            if (mValues == null || mValues.length == 0) {
                setValues(PropertyValuesHolder.ofInt("", values));
            } else {
                PropertyValuesHolder valuesHolder = mValues[0];
                valuesHolder.setIntValues(values);
            }
            // New property/values/target should cause re-initialization prior to starting
            mInitialized = false;
        }
    

    还是走上一个函数a public void setValues(PropertyValuesHolder... values)最终将数据塞给mValuesMap保存下来

    正式start()

    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();
        }
    

    这段代码逻辑还是比较清楚的,在比较与mAnimations,mPendingAnimations,mDelayedAnims数组中找出是否存在当前动画,先cancel掉。
    接着log,然后 super.start();

     @Override
        public void start() {
            start(false);
        }
    
    private void start(boolean playBackwards) {
            if (Looper.myLooper() == null) {
                throw new AndroidRuntimeException("Animators may only be run on Looper threads");
            }
            mReversing = playBackwards;
            mPlayingBackwards = playBackwards;
            if (playBackwards && mSeekFraction != -1) {
                if (mSeekFraction == 0 && mCurrentIteration == 0) {
                    // special case: reversing from seek-to-0 should act as if not seeked at all
                    mSeekFraction = 0;
                } else if (mRepeatCount == INFINITE) {
                    mSeekFraction = 1 - (mSeekFraction % 1);
                } else {
                    mSeekFraction = 1 + mRepeatCount - (mCurrentIteration + mSeekFraction);
                }
                mCurrentIteration = (int) mSeekFraction;
                mSeekFraction = mSeekFraction % 1;
            }
            if (mCurrentIteration > 0 && mRepeatMode == REVERSE &&
                    (mCurrentIteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) {
                // if we were seeked to some other iteration in a reversing animator,
                // figure out the correct direction to start playing based on the iteration
                if (playBackwards) {
                    mPlayingBackwards = (mCurrentIteration % 2) == 0;
                } else {
                    mPlayingBackwards = (mCurrentIteration % 2) != 0;
                }
            }
            int prevPlayingState = mPlayingState;
            mPlayingState = STOPPED;
            mStarted = true;
            mStartedDelay = false;
            mPaused = false;
            updateScaledDuration(); // in case the scale factor has changed since creation time
            AnimationHandler animationHandler = getOrCreateAnimationHandler();
            animationHandler.mPendingAnimations.add(this);
            if (mStartDelay == 0) {
                // This sets the initial value of the animation, prior to actually starting it running
                if (prevPlayingState != SEEKED) {
                    setCurrentPlayTime(0);
                }
                mPlayingState = STOPPED;
                mRunning = true;
                notifyStartListeners();
            }
            animationHandler.start();
        }
    

    AnimationHandler是一个单例对象,getOrCreateAnimationHandler()获取。 不同属性动画版本,这里有所区别。 animationHandler.start();

    public void start() {
                scheduleAnimation();
            }
    

    继续看

      private void scheduleAnimation() {
                if (!mAnimationScheduled) {
                    mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
                    mAnimationScheduled = true;
                }
            }
    

    原来是在这里mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null); Choreographer机制,用于同Vsync机制配合,实现统一调度界面绘图
    最终调用

    private void postCallbackDelayedInternal(int callbackType,
                Object action, Object token, long delayMillis) {
            if (DEBUG_FRAMES) {
                Log.d(TAG, "PostCallback: type=" + callbackType
                        + ", action=" + action + ", token=" + token
                        + ", delayMillis=" + delayMillis);
            }
    
            synchronized (mLock) {
                final long now = SystemClock.uptimeMillis();
                final long dueTime = now + delayMillis;
                mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
    
                if (dueTime <= now) {
                    scheduleFrameLocked(now);
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                    msg.arg1 = callbackType;
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtTime(msg, dueTime);
                }
            }
        }
    

    mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);根据类型加入不同的队列
    Android系统Choreographer机制实现过程
    当VSYNC信号到达时,Choreographer doFrame()函数被调用。代码较多,中间省略掉

    void doFrame(long frameTimeNanos, int frame) {
            ...
            try {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
    
                mFrameInfo.markInputHandlingStart();
                doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
    
                mFrameInfo.markAnimationsStart();
                doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
    
                mFrameInfo.markPerformTraversalsStart();
                doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
    
                doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
    
            if (DEBUG_FRAMES) {
                final long endNanos = System.nanoTime();
                Log.d(TAG, "Frame " + frame + ": Finished, took "
                        + (endNanos - startNanos) * 0.000001f + " ms, latency "
                        + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
            }
        }
    

    于是

    void doCallbacks(int callbackType, long frameTimeNanos) {  
        CallbackRecord callbacks;  
        synchronized (mLock) {  
            final long now = SystemClock.uptimeMillis();  
            //从指定类型的CallbackQueue队列中查找执行时间到的CallbackRecord  
            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);  
            if (callbacks == null) {  
                return;  
            }  
            mCallbacksRunning = true;  
        }  
        try {  
            //由于CallbackQueues是按时间先后顺序排序的,因此遍历执行所有时间到的CallbackRecord 。 这个record是CallbackQueues post的时候加入的。
            for (CallbackRecord c = callbacks; c != null; c = c.next) {  
                c.run(frameTimeNanos);  
            }  
        } finally {  
            synchronized (mLock) {  
                mCallbacksRunning = false;  
                do {  
                    final CallbackRecord next = callbacks.next;  
                    recycleCallbackLocked(callbacks);  
                    callbacks = next;  
                } while (callbacks != null);  
            }  
        }  
    }  
    

    for (CallbackRecord c = callbacks; c != null; c = c.next) {
    c.run(frameTimeNanos);
    }
    这句即调用mAnimate的run方法

    final Runnable mAnimate = new Runnable() {
                @Override
                public void run() {
                    mAnimationScheduled = false;
                    doAnimationFrame(mChoreographer.getFrameTime());
                }
            };
    

    继续走doAnimationFrame(mChoreographer.getFrameTime());

    void doAnimationFrame(long frameTime) {
                mLastFrameTime = frameTime;
    
                // mPendingAnimations holds any animations that have requested to be started
                // We're going to clear mPendingAnimations, but starting animation may
                // cause more to be added to the pending list (for example, if one animation
                // starting triggers another starting). So we loop until mPendingAnimations
                // is empty.
                while (mPendingAnimations.size() > 0) {
                    ArrayList<ValueAnimator> pendingCopy =
                            (ArrayList<ValueAnimator>) mPendingAnimations.clone();
                    mPendingAnimations.clear();
                    int count = pendingCopy.size();
                    for (int i = 0; i < count; ++i) {
                        ValueAnimator anim = pendingCopy.get(i);
                        // If the animation has a startDelay, place it on the delayed list
                        if (anim.mStartDelay == 0) {
                            anim.startAnimation(this);
                        } else {
                            mDelayedAnims.add(anim);
                        }
                    }
                }
    
                // Next, process animations currently sitting on the delayed queue, adding
                // them to the active animations if they are ready
                int numDelayedAnims = mDelayedAnims.size();
                for (int i = 0; i < numDelayedAnims; ++i) {
                    ValueAnimator anim = mDelayedAnims.get(i);
                    if (anim.delayedAnimationFrame(frameTime)) {
                        mReadyAnims.add(anim);
                    }
                }
                int numReadyAnims = mReadyAnims.size();
                if (numReadyAnims > 0) {
                    for (int i = 0; i < numReadyAnims; ++i) {
                        ValueAnimator anim = mReadyAnims.get(i);
                        anim.startAnimation(this);
                        anim.mRunning = true;
                        mDelayedAnims.remove(anim);
                    }
                    mReadyAnims.clear();
                }
    
                // Now process all active animations. The return value from animationFrame()
                // tells the handler whether it should now be ended
                int numAnims = mAnimations.size();
                for (int i = 0; i < numAnims; ++i) {
                    mTmpAnimations.add(mAnimations.get(i));
                }
                for (int i = 0; i < numAnims; ++i) {
                    ValueAnimator anim = mTmpAnimations.get(i);
                    if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
                        mEndingAnims.add(anim);
                    }
                }
                mTmpAnimations.clear();
                if (mEndingAnims.size() > 0) {
                    for (int i = 0; i < mEndingAnims.size(); ++i) {
                        mEndingAnims.get(i).endAnimation(this);
                    }
                    mEndingAnims.clear();
                }
    
                // Schedule final commit for the frame.
                mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mCommit, null);
    
                // If there are still active or delayed animations, schedule a future call to
                // onAnimate to process the next frame of the animations.
                if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
                    scheduleAnimation();
                }
            }
    

    这里有好几个重要的逻辑,其实处理的主要调度在这里发出:

    1 首先遍历mPendingAnimations队列 :

    a 要延迟启动,加入mDelayedAnims队列
    b 如果不是延迟则调用startAnimation(AnimationHandler handler)方法

    2 接着处理mDelayedAnims延迟队列,经过delayedAnimationFrame判断是否唤醒当前的动画

    如果唤醒的话将ValueAnimator对象添加到mReadyAnims准备列表中;

    3 接下来处理mReadyAnims列表,遍历该列表取出ValueAnimator对象并调用startAnimation(AnimationHandler handler)方法

    4 下一步将处理mAnimations动画列表,通过遍历将当前要启动的动画倒装在临时列表mTmpAnimations,遍历临时列表调用anim.doAnimationFrame(frameTime)方法,通过该方法的返回值判断是否为动画的最后一帧,若是,则将ValueAnimator对象添加到mEndingAnims结束动画列表。遍历结束后清除临时列表mTmpAnimations;

    5 最后遍历mEndingAnims结束列表调用endAnimation()方法,遍历结束后清除mEndingAnims列表。

    6 mAnimations和mDelayedAnims两个列表,只要任何一个不为空还会调用scheduleAnimation方法,形成了循环。

    参考 http://icedcap.github.io/2016/06/21/Android%E5%8A%A8%E7%94%BB%E5%AE%8C%E5%85%A8%E6%80%BB%E7%BB%93/

    image.png

    先看ValueAnimator的startAnimation(AnimationHandler handler),好吧,一系列初始化


    image.png image.png

    这里先initAnimation之后就notifyStartListeners
    先看listener

    image.png

    原来是这里回调listener开始动画。

    image.png image.png

    接着继续看,动画执行:

    image.png
    final boolean doAnimationFrame(long frameTime) {
            if (mPlayingState == STOPPED) {
                mPlayingState = RUNNING;
                if (mSeekFraction < 0) {
                    mStartTime = frameTime;
                } else {
                    long seekTime = (long) (mDuration * mSeekFraction);
                    mStartTime = frameTime - seekTime;
                    mSeekFraction = -1;
                }
                mStartTimeCommitted = false; // allow start time to be compensated for jank
            }
            if (mPaused) {
                if (mPauseTime < 0) {
                    mPauseTime = frameTime;
                }
                return false;
            } else if (mResumed) {
                mResumed = false;
                if (mPauseTime > 0) {
                    // Offset by the duration that the animation was paused
                    mStartTime += (frameTime - mPauseTime);
                    mStartTimeCommitted = false; // allow start time to be compensated for jank
                }
            }
            // The frame time might be before the start time during the first frame of
            // an animation.  The "current time" must always be on or after the start
            // time to avoid animating frames at negative time intervals.  In practice, this
            // is very rare and only happens when seeking backwards.
            final long currentTime = Math.max(frameTime, mStartTime);
            return animationFrame(currentTime);
        }
    
    boolean animationFrame(long currentTime) {
            boolean done = false;
            switch (mPlayingState) {
            case RUNNING:
            case SEEKED:
                float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
                if (mDuration == 0 && mRepeatCount != INFINITE) {
                    // Skip to the end
                    mCurrentIteration = mRepeatCount;
                    if (!mReversing) {
                        mPlayingBackwards = false;
                    }
                }
                if (fraction >= 1f) {
                    if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
                        // Time to repeat
                        if (mListeners != null) {
                            int numListeners = mListeners.size();
                            for (int i = 0; i < numListeners; ++i) {
                                mListeners.get(i).onAnimationRepeat(this);
                            }
                        }
                        if (mRepeatMode == REVERSE) {
                            mPlayingBackwards = !mPlayingBackwards;
                        }
                        mCurrentIteration += (int) fraction;
                        fraction = fraction % 1f;
                        mStartTime += mDuration;
                        // Note: We do not need to update the value of mStartTimeCommitted here
                        // since we just added a duration offset.
                    } else {
                        done = true;
                        fraction = Math.min(fraction, 1.0f);
                    }
                }
                if (mPlayingBackwards) {
                    fraction = 1f - fraction;
                }
                animateValue(fraction);
                break;
            }
    
            return done;
        }
    

    mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE 条件内回调了onAnimationRepeat(this)。 而改函数继续调用了 animateValue(fraction); fraction 动画进度。然后先调用子类ObjectAnimator的animateValue

    image.png

    注意到先调用了ValueAnimator super.animateValue(fraction);

       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将根据Keyframes获取到的值塞给mAnimatedValue

       void calculateValue(float fraction) {
            Object value = mKeyframes.getValue(fraction);
            mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
        }
    

    这里回调了动画的进度mUpdateListeners.get(i).onAnimationUpdate(this),很多时候可以根据这个回调来完成我们想要的一些效果,如贝塞尔曲线运动等。animateValue然后回到子类ObjectAnimator的void animateValue(float fraction) 方法

    image.png image.png

    此时调用PropertyValuesHolder的 void setAnimatedValue(Object target)

    image.png

    可见是使用反射方式给对应属性值设置了value值。

    里面的逻辑比较清晰,但是调用太多了,读起来还是比较费劲的。最后给出一下整个的时序:
    Animator#start() --> ValueAnimator#start() --> ValueAnimator# start(false) --> AnimationHandler#start()--> scheduleAnimation() -->
    --> Choreographer#postCallback(Choreographer.CALLBACK_ANIMATION ....(省略) -->

    AnimationHandler # void doAnimationFrame(long frameTime)--> ValueAnimator # startAnimation(AnimationHandler) -->ValueAnimator # notifyStartListeners --> AnimatorListener#onAnimationStart() -->ValueAnimator # doAnimationFrame() -->

    ValueAnimator # animationFrame(currentTime) --> ObjectAnimator#animateValue(fraction) --> ValueAnimator # animateValue(fraction) --> AnimatorListener#onAnimationUpdate(this) -->PropertyValuesHolder # setAnimatedValue(target)

    相关文章

      网友评论

        本文标题:属性动画源码分析

        本文链接:https://www.haomeiwen.com/subject/xewnhxtx.html