Animator相关源码分析

xiaoxiao2021-03-01  26

本篇分析与Animator相关的源码

开始

以下为Animator相关类图

Animator是抽象类,ValueAnimator实现了Animator,ObjectAnimator和TimeAnimator继承了ValueAnimator。通常开发直接使用ValueAnimator也就可以实现所有动画了。由此,ValueAnimator算是Android动画的核心Class了,所以解析动画入口点放置在ValueAnimator上。

通常设置一个ValueAnimator的方法有:

valueAnim = ValueAnimator.ofFloat(0f, 1f); valueAnim .setDuration(500); valueAnim .setRepeatMode(ValueAnimator.RESTART); valueAnim .setRepeatCount(ValueAnimator.INFINITE); valueAnim .setInterpolator(new LinearInterpolator()); valueAnim .addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); ... }); valueAnim.setStartDelay(500); valueAnim .start();

下面以几个问题为目标解析ValueAnimator。

一、ValueAnimator如何实现计时?

从start()入手:

... private void start(boolean playBackwards) { // playBackwards Whether the ValueAnimator should start playing in reverse. ... addAnimationCallback(0);// 真正开启计时 ... } ... @Override public void start() { start(false); } ... private void addAnimationCallback(long delay) { if (!mSelfPulse) { return; } // this 即ValueAnimator实现AnimationFrameCallback接口的doAnimationFrame() getAnimationHandler().addAnimationFrameCallback(this, delay); } ...

ValueAnimator将计时抛到了AnimatorHandler,ValueAnimator仅接收计时的结果,由doAnimationFrame()接收。

再看AnimationHandler:

... public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) { if (mAnimationCallbacks.size() == 0) { // 第一次统一使用mFrameCallback接受计时结果 getProvider().postFrameCallback(mFrameCallback); } if (!mAnimationCallbacks.contains(callback)) { // mFrameCallback通过mAnimationCallbacks实现监听分发 mAnimationCallbacks.add(callback); } if (delay > 0) { mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay)); } } ... private AnimationFrameCallbackProvider getProvider() { if (mProvider == null) { mProvider = new MyFrameCallbackProvider(); } return mProvider; }

AnimationHandler又抛到了MyFrameCallbackProvider:

private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider { final Choreographer mChoreographer = Choreographer.getInstance(); @Override public void postFrameCallback(Choreographer.FrameCallback callback) { mChoreographer.postFrameCallback(callback); } ... }

接着抛到Choreographer:

... private final FrameHandler mHandler; ... public void postFrameCallback(FrameCallback callback) { postFrameCallbackDelayed(callback, 0); } ... public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { if (callback == null) { throw new IllegalArgumentException("callback must not be null"); } postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN, delayMillis); } ... private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { ... synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { // 此处在MyFrameCallbackProvider没有实现postFrameCallbackDelayed方法,所以不会调用,自定义FrameCallbackProvider可以实现 scheduleFrameLocked(now); } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); msg.arg1 = callbackType; msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, dueTime); } } } ... private final class FrameHandler extends Handler { public FrameHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DO_FRAME: doFrame(System.nanoTime(), 0); break; case MSG_DO_SCHEDULE_VSYNC: doScheduleVsync(); break; case MSG_DO_SCHEDULE_CALLBACK: doScheduleCallback(msg.arg1); break; } } }

Choreographer内部持有FrameHandler,通过Handler的sendMessageAtTime方法实现。到此,计时的位置已经找到了,但是Animator为什么要抛这么多层?抛的好处是什么呢?在此我们需要先了解一些ValueAnimator与AnimatorHandler之间的关系:

这里不贴源码,只阐述:

1)AnimationHandler内部有:

     public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();

     确保一个线程下只有一个AnimationHandler。

2)当线程内有一个ValueAnimator start()之后,内部Handler一直在计时,不管外部ValueAnimator是否有在运行。当然,这里指的是通过MyFrameCallbackProvider是这样的,它并没有提供停止的方法,如果我们自定义自然是可以实现的。其次,当有一个新的Animator开始start时,主动开始一次mHandler.sendMessageAtTime(),进入一个SCHEDULE状态,而后进入FRAME状态,每隔一个时间片就刷新一次。

3)ValueAnimator的延迟、反转、重复、暂停、唤醒等操作都在其内部内部实现,ValueAnimator与AnimationHandler单纯就是时间片更新监听的关系。

4)我们可以通过ValueAnimator.setFrameDelay(5); // 默认是10ms,设置为5ms更新一次时间片,设置的是AnimationHandler -> MyFrameCallbackProvider -> Choreographer 的sFrameDelay字段,会强制对当前线程下所有的ValueAnimator适用。

由上可看出:抛到AnimationHandler是合理的。AnimationHandler再抛到MyFrameCallbackProvider,是桥接模式的使用,方便后续扩展。Choreographer为我们自定义的FrameCallbackProvider提供统一的计时方法,所以MyFrameCallbackProvider将计时再抛到Choreographer也是合理。

二、ValueAnimator如何实现延迟、反转、重复次数?

入口点:ValueAnimator的doAnimationFrame();

public final boolean doAnimationFrame(long frameTime) { // frameTime为系统时间 if (mStartTime < 0) { // start()设置mStartTime = -1,此处为初始化mStartTime // mStartDelay为外部设置(setStartDelay())的延迟时间ms;默认sDurationScale = 1.0f mStartTime = mReversing ? frameTime : frameTime + (long) (mStartDelay * sDurationScale); } // 暂停和唤醒处理 if (mPaused) { mPauseTime = frameTime; removeAnimationCallback(); return false; } else if (mResumed) { mResumed = false; if (mPauseTime > 0) { 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; } 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; // 是否开始新的Repeat final boolean newIteration = (int) fraction > (int) lastFraction; final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) && (mRepeatCount != INFINITE); // mRepeatCount == INFINITE,lastIterationFinished永远为false,再根据newIteration执行下方的① if (scaledDuration == 0) {// 时间为0时,不考虑其它 done = true; } else if (newIteration && !lastIterationFinished) {// ① 需要开始新的Repeat if (mListeners != null) { // 执行Repeat监听 int numListeners = mListeners.size(); for (int i = 0; i < numListeners; ++i) { mListeners.get(i).onAnimationRepeat(this); } } } else if (lastIterationFinished) {// 不需要开始新的repeat的正常情况 done = true; } mOverallFraction = clampFraction(fraction); float currentIterationFraction = getCurrentIterationFraction(mOverallFraction, mReversing); // 取值 animateValue(currentIterationFraction); // currentIterationFraction [0f,1f] } return done; } ... private float getCurrentIterationFraction(float fraction, boolean inReverse) { fraction = clampFraction(fraction); int iteration = getCurrentIteration(fraction); float currentFraction = fraction - iteration; return shouldPlayBackward(iteration, inReverse) ? 1f - currentFraction : currentFraction; // 反转判断 }

延时:代码主要在doAnimationFrame()。外部设置setStartDelay(),这里就将开始时刻定为:当前时间片+delay的时间。

重复:代码主要在animateBasedOnTime()。看代码中的注释,mRepeatCount == INFINITE 则一直repeat,否则计算我们设置的repeat次数。

反转:代码主要在getCurrentIterationFraction()。将待传入animateValue的值[0f,1f]判断是否取反。

以上我们就将这三个方法都了解完了

valueAnim .setRepeatMode(ValueAnimator.RESTART);

valueAnim .setRepeatCount(ValueAnimator.INFINITE);

valueAnim.setStartDelay(500);

三、插值器如何实现?

mInterpolator只被ValueAnimator持有:

@Override public void setInterpolator(TimeInterpolator value) { if (value != null) { mInterpolator = value; } else { mInterpolator = new LinearInterpolator(); } } ... void animateValue(float fraction) { // fraction [0f,1f] fraction = mInterpolator.getInterpolation(fraction); // mInterpolator在代码中唯一使用的地方 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); } } }

mInterpolator仅仅在UpdateListener之前对值进行换算,传递给animateValue是范围在[0f,1f]线性的值(可以参考第二个问题的解析),然后根据不同的插值器进行换算实现结果。

四、再看下ObjectAnimator和TimeAnimator

ObjectAnimator

ObjectAnimator继承于ValueAnimator,先看其构造源码:

... private <T> ObjectAnimator(T target, Property<T, ?> property) { setTarget(target); setProperty(property); } ... public static ObjectAnimator ofInt(Object target, String propertyName, int... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setIntValues(values); return anim; } ... @Override public void setTarget(@Nullable Object target) { final Object oldTarget = getTarget(); if (oldTarget != target) { if (isStarted()) { cancel(); } mTarget = target == null ? null : new WeakReference<Object>(target); mInitialized = false; } } ... 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); } mInitialized = false; }

target为ObjectAnimator内部弱引用,mValues是ValueAnimator的成员变量,大部分动画的代码都由ValueAnimator来实现了。

再看ObjectAnimator如何为成员变量进行动态赋值的:

... public Object getTarget() { return mTarget == null ? null : mTarget.get(); } ... @Override void animateValue(float fraction) { final Object target = getTarget(); if (mTarget != null && target == null) { cancel(); return; } super.animateValue(fraction); int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { mValues[i].setAnimatedValue(target); } }

重载animateValue(),而后对所有的values进行赋值。

TimeAnimator

TimeAnimator.TimeListener:

这个类比较简单,代码很少,主要是对ValueAnimator扩展,实现对动画每一帧的监听。

 

 

转载请注明原文地址: https://www.6miu.com/read-4050106.html

最新回复(0)