属性动画源码分析

来源:互联网 发布:最新网络电视机 编辑:程序博客网 时间:2024/05/21 09:11

详见我的简书 http://www.jianshu.com/p/29fbf22bbbe3

分析版本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)

原创粉丝点击