Animator属性动画源码

QuibblerQuibbler 2021-11-27 约 62 分钟 2350 次阅读

Animator属性动画源码

仔细看看属性动画的源码,加深对动画实现原理的了解。ObjectAnimator继承自ValueAnimator,本篇主要以ValueAnimator为主。关于属性动画,详见之前两篇介绍属性动画的文章:属性动画:ValueAnimator和属性动画:ObjectAnimator。

1、属性动画的构造

得益于框架优秀的设计,构造一个属性动画对象很简单,举个简单的例子:

//ValueAnimator动画
    ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
    
    //ObjectAnimator动画
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0, 1);

从ValueAnimator的ofInt()方法开始,使用该方法可以获得一个ValueAnimator实例:

public static ValueAnimator ofInt(int... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setIntValues(values);
        return anim;
    }

ofInt()方法中先用ValueAnimator默认构造函数直接构造一个实例;再调用setIntValues(values)方法设置初始化,其中主要涉及PropertyValuesHolder、Keyframes等属性创建。

public void setIntValues(int... values) {
        if (values == null || values.length == 0) {
            return;
        }
        
        //是否已经设置过PropertyValuesHolder属性
        if (mValues == null || mValues.length == 0) {
            //创建PropertyValuesHolder,并添加到当前ValueAnimator属性动画中。
            setValues(PropertyValuesHolder.ofInt("", values));
        } else {
            //直接更新已有的PropertyValuesHolder属性值
            PropertyValuesHolder valuesHolder = mValues[0];
            valuesHolder.setIntValues(values);
        }
        // New property/values/target should cause re-initialization prior to starting
        mInitialized = false;
    }

创建特定的PropertyValuesHolder对象并添加到当前ValueAnimator属性动画中。

public static PropertyValuesHolder ofInt(String propertyName, int... values) {
        //这里为int类型,创建返回IntPropertyValuesHolder
        return new IntPropertyValuesHolder(propertyName, values);
    }

在IntPropertyValuesHolder的构造方法中设置关键帧,使用PropertyValuesHolder的setIntValues(int... values)方法:

public void setIntValues(int... values) {
        mValueType = int.class;
        //调用KeyframeSet的ofInt方法,创建关键帧集合
        mKeyframes = KeyframeSet.ofInt(values);
    }

随后又会使用Keyframe创建关键帧,并添加到关键帧集合KeyframeSet中:

public static KeyframeSet ofInt(int... values) {
        int numKeyframes = values.length;
        IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
        if (numKeyframes == 1) {
            keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
            keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
        } else {
            keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
            for (int i = 1; i < numKeyframes; ++i) {
                keyframes[i] =
                        (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
            }
        }
        //同样,参数为int,返回的是IntKeyframeSet。此外,还有FloatKeyframeSet、KeyframeSet
        return new IntKeyframeSet(keyframes);
    }

源码的分支逻辑很多,阅读源码的时候只需要关注主要流程。手动画时序图费时间,直接用SequenceDiagram基于API 31的源码,生成了创建ValueAnimator属性动画的时序图,如下:


类似的,创建ObjectAnimator的时序图:


2、属性动画的执行

拿到属性动画对象后,再设置插值器、监听器、动画时长等属性,就可以播放动画。

//设置插值器,默认为AccelerateDecelerateInterpolator。如果设置为null,则使用LinearInterpolator
    valueAnimator.setInterpolator(new AnticipateInterpolator());
    
    //设置动画时长,默认300ms
    valueAnimator.setDuration(500);
    
    //ValueAnimator动画的使用就是监听值的变化,自行设置动画值。
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float val = (float) animation.getAnimatedValue();
            //TODO(use val)
        }
    });
    
    //开启动画,在UI线程 或者 带Looper的子线程也可
    valueAnimator.start();

2.1、播放动画

从start()方法为入口,开始阅读源码。如果用reverse()开始动画,动画则是反向播放。

public void start() {
        //正向播放动画,而不是反向播放动画。
        start(false);
    }

接着调用start(boolean playBackwards)。这里虽然没有强制一定要在主线程才能播放动画,但是要求所在线程必须拥有Looper。动画将在调用线程上运行,如果在动画过程中更新View的属性,显然,这需要在UI线程才能进行操作。

private void start(boolean playBackwards) {
        //必须在有Looper的线程调用,虽然这里没有强制UI线程,
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        ...
        
        //一系列动画相关的状态设置
        mStarted = true;
        mPaused = false;
        mRunning = false;
        mAnimationEndRequested = false;
        ...
        
        //真正触发动画的方法在这里
        addAnimationCallback(0);
        if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
            // 通知监听器等待动画开始
            startAnimation();
            ...
        }
    }

在start(boolean playBackwards)方法中调用到两个关键方法:一个是addAnimationCallback(long delay),另一个是startAnimation()。从方法名看,会误以为startAnimation()是开启动画的方法,其实addAnimationCallback(long delay)方法才是:

private void addAnimationCallback(long delay) {
        if (!mSelfPulse) {
            return;
        }
        getAnimationHandler().addAnimationFrameCallback(this, delay);
    }

AnimationHandler类,顾名思义,进行动画处理。

public AnimationHandler getAnimationHandler() {
        return mAnimationHandler != null ? mAnimationHandler : AnimationHandler.getInstance();
    }

借助ThreadLocal,执行动画所在的线程(而不是创建线程)可以拿到唯一的一个AnimationHandler实例,用来处理当前线程中的所有动画。

public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
    public static AnimationHandler getInstance() {
        if (sAnimatorHandler.get() == null) {
            sAnimatorHandler.set(new AnimationHandler());
        }
        return sAnimatorHandler.get();
    }

调用AnimationHandler的addAnimationFrameCallback(AnimationFrameCallback , delay)方法先注册一个Choreographer.FrameCallback回调给Choreographer,再将ValueAnimator注册到AnimationHandler中。

public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        if (mAnimationCallbacks.size() == 0) {
           //将AnimationHandler中的mFrameCallback回调注册给Choreographer
            getProvider().postFrameCallback(mFrameCallback);
        }
        if (!mAnimationCallbacks.contains(callback)) {
            //将Animator属性动画实例注册到AnimationHandler
            mAnimationCallbacks.add(callback);
        }
        ...
    }

AnimationHandler中的MyFrameCallbackProvider内部类实现AnimationFrameCallbackProvider接口,其中有一个Choreographer实例,Choreographer不是本篇重点,关于Choreographer详见Choreographer源码阅读一文。

/**
     * Default provider of timing pulse that uses Choreographer for frame callbacks.
     */
    private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
    
        //Choreographer实例
        final Choreographer mChoreographer = Choreographer.getInstance();
        
        //注册Callback到Choreographer中
        @Override
        public void postFrameCallback(Choreographer.FrameCallback callback) {
            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);
        }
    }

mFrameCallback是定义在AnimationHandler类中的Choreographer.FrameCallback回调。

private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                getProvider().postFrameCallback(this);
            }
        }
    };

在addAnimationFrameCallback(AnimationFrameCallback , delay)方法中被注册给Choreographer。

public void postFrameCallback(FrameCallback callback) {
        postFrameCallbackDelayed(callback, 0);
    }

经过几个方法的调用传递,从postFrameCallbackDelayed(FrameCallback ,delayMillis)方法:

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

再到postCallbackDelayedInternal()方法:

private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        ...
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            
            //这里的action就是传入的mFrameCallback
            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);
            }
        }
    }

scheduleFrameLocked(long now)方法中检查是否启用USE_VSYNC,如果没有就用消息机制刷新。

private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            //检查是否启用USE_VSYNC,默认为true
            if (USE_VSYNC) {
                ...
                //在Looper线程上执行
                if (isRunningOnLooperThreadLocked()) {
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg);
                }
            } else {
                //如果没有启用USE_VSYNC,则通过异步消息执行屏幕刷新
                final long nextFrameTime = Math.max(
                        mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                }
                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
    }

Choreographer中的USE_VSYNC属性默认为true,为动画和绘图启用垂直同步。

// Enable/disable vsync for animations and drawing.
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
            "debug.choreographer.vsync", true);

最终执行scheduleVsyncLocked()请求底层VSYNC信号:

private void scheduleVsyncLocked() {
        mDisplayEventReceiver.scheduleVsync();
    }

mDisplayEventReceiver为FrameDisplayEventReceiver实例,FrameDisplayEventReceiver继承自DisplayEventReceiver,用于接收同步脉冲信号VSYNC,在Choreographer构造方法中初始化:

private Choreographer(Looper looper, int vsyncSource) {
        mLooper = looper;
        mHandler = new FrameHandler(looper);
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource) : null;
        ...
    }

在DisplayEventReceiver的scheduleVsync()方法中,又调用了Native方法nativeScheduleVsync(long receiverPtr),向SurfaceFlinger服务注册,请求系统发送脉冲信号开启动画。

public void scheduleVsync() {
        nativeScheduleVsync(mReceiverPtr);
    }

Native层处理完会回调DisplayEventReceiver的dispatchVsync()函数,至于底层如何处理,这里就不往下卷了。

跟随源码看到这里,将属性动画ValueAnimator启动的主要流程走了一遍。简化的时序图如下:


ObjectAnimator继承自ValueAnimator,开启动画流程和ValueAnimator类似,只是在start()中多了一个AnimationHandler的autoCancelBasedOn(ObjectAnimator )方法调用:


2.2、动画执行

Native收到VSYNC同步脉冲信号,就会回调DisplayEventReceiver的dispatchVsync()方法,类似发布订阅模式。

// Called from native code.
    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
            long frameTimelineVsyncId, long frameDeadline, long frameInterval) {
        onVsync(timestampNanos, physicalDisplayId, frame,
                new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval));
    }

FrameDisplayEventReceiver继承自DisplayEventReceiver,重写了DisplayEventReceiver中的onVsync()空方法。在该方法中向FrameHandler发送消息,

private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
        ...
        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
                VsyncEventData vsyncEventData) {
            ...
                //创建发送的消息,虽然没有指明what或者其它标志,但是Callback传递的是自身
                //因为FrameDisplayEventReceiver本身继承自Runnable
                Message msg = Message.obtain(mHandler, this);
                msg.setAsynchronous(true);
                //向FrameHandler发送消息
                mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
            ...
        }
        
        @Override
        public void run() {
            mHavePendingVsync = false;
            //最后Handler处理上面onVsync()发送的消息时,会执行该方法。
            doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
        }
    }

由于发送的Message中指明callback为FrameDisplayEventReceiver本身,所以会执行run()方法,另见Handler中Callback的作用一文。进而执行Choreographer中的doFrame()方法:

void doFrame(long frameTimeNanos, int frame,
            DisplayEventReceiver.VsyncEventData vsyncEventData) {
        ...
            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
            mFrameInfo.markAnimationsStart();
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos,
                    frameIntervalNanos);
            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
        ...
    }

动画对应执行的Callback类型是CALLBACK_ANIMATION:

/**
     * Callback type: Animation callback.  Runs before {@link #CALLBACK_INSETS_ANIMATION}.
     * @hide
     */
    @TestApi
    public static final int CALLBACK_ANIMATION = 1;

紧接着调用doCallbacks(...)方法,该方法比较长,看源码就得选择性忽略,真正有用的浓缩成下面几行:

void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) {
        CallbackRecord callbacks;
            ...
            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                    now / TimeUtils.NANOS_PER_MS);
            ...
            for (CallbackRecord c = callbacks; c != null; c = c.next) {
                c.run(frameTimeNanos);
            }
            ...
    }

还记得Choreographer中的mCallbackQueues[]吗?在前面开启动画的过程中就使用postCallbackDelayedInternal(...)将AnimationHandler中的Choreographer.FrameCallback回调mFrameCallback注册到mCallbackQueues[CALLBACK_ANIMATION]里。

从mCallbackQueues[CALLBACK_ANIMATION]中拿到CallbackRecord对象,执行其run()方法:

private static final class CallbackRecord {
        ...
        public Object action; // Runnable or FrameCallback
        ...
        public void run(long frameTimeNanos) {
            if (token == FRAME_CALLBACK_TOKEN) {
                ((FrameCallback)action).doFrame(frameTimeNanos);
            } else {
                ((Runnable)action).run();
            }
        }
    }

        CallbackRecord中的action就是AnimationHandler中的mFrameCallback回调对象。这里注意,如果还有动画回调对象注册,也就是动画没有执行完,会继续请求下一个VSYNC信号,从而稳定的进行动画。

private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                getProvider().postFrameCallback(this);
            }
        }
    };

在Choreographer.FrameCallback回调执行AnimationHandler的doAnimationFrame(long frameTime)方法

private void doAnimationFrame(long frameTime) {
        ...
        for (int i = 0; i < size; i++) {
            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
            ...
            callback.doAnimationFrame(frameTime);
            ...
        }
        cleanUpList();
    }

        mAnimationCallbacks很眼熟,就是前面开始播放ValueAnimator动画的时候,通过addAnimationCallback(long delay)方法:

private void addAnimationCallback(long delay) {
        if (!mSelfPulse) {
            return;
        }
        getAnimationHandler().addAnimationFrameCallback(this, delay);
    }

将属性动画ValueAnimator注册添加到AnimationHandler的中,存在mAnimationCallbacks集合里:

/**
     * Register to get a callback on the next frame after the delay.
     */
    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        //将AnimationHandler中的mFrameCallback注册给Choreographer
        if (mAnimationCallbacks.size() == 0) {
            getProvider().postFrameCallback(mFrameCallback);
        }
        
        //将ValueAnimator添加到动画回调集合中
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }
        ...
    }

        ValueAnimator实现了AnimationHandler中的AnimationFrameCallback接口,doAnimationFrame(long frameTime)方法实现如下:

public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {
        
            public final boolean doAnimationFrame(long frameTime) {
            ...
            
            // 处理动画的暂停和继续,这里的源码需要留意一下!后面第4节会再次提到
            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);
                }
            }
            
            //此处忽略大量状态处理
            ...
            
            //基于事件计算动画进度
            boolean finished = animateBasedOnTime(currentTime);
            
            //判断动画是否结束
            if (finished) {
                //处理动画结束
                endAnimation();
            }
            return finished;
        }
        
    }

ValueAnimator中的animateBasedOnTime(currentTime)方法正如方法名,依据当前时间回调执行动画:

boolean animateBasedOnTime(long currentTime) {
        boolean done = false;
        if (mRunning) {
            ...
            //计算动画值的变化
            animateValue(currentIterationFraction);
        }
        return done;
    }

紧接着执行animateValue(float fraction)方法。计算当前动画值。在这里会通知注册的AnimatorUpdateListener监听器,在这里开发者根据值的变化设置View的属性,形成动画。

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) {
                //回调动画监听器onAnimationUpdate,更新值
                mUpdateListeners.get(i).onAnimationUpdate(this);
            }
        }
    }

ValueAnimator动画过程中的主要流程都深入的了解一遍,输出一下简化的流程图:


同样的,ObjectAnimator动画回调和ValueAnimator类似,最后更新值的变化操作不太一样,使用ObjectAnimator不需要手动更新View属性值。这是因为animateValue(float fraction)方法在ValueAnimator的子类ObjectAnimator中有所不同,不只是单纯的计算动画值的变化,由内部的PropertyValuesHolder执行setAnimatedValue(Object target)用反射设置View的属性(反射细节这里暂不深挖),从而形成动画。

@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) {
            mValues[i].setAnimatedValue(target);
        }
    }

ObjectAnimator动画总体流程和ValueAnimator类似:


反射的细节,这里不再赘述,由于ObjectAnimator多了一个反射过程,从动画的性能考量,使用ValueAnimator要比ObjectAnimator好一些。ObjectAnimator对动画属性操作封装的较好,开发用起来更方便。

3、动画的终止

前面了解了动画的启动start(),接下来看看动画的终止,有两个方法可以终止动画:cancel()和end()。两个方法最后都会调用endAnimation()方法终止动画:

private void endAnimation() {
        //如果已经在结束中,直接返回
        if (mAnimationEndRequested) {
            return;
        }
        
        //从AnimationHandler中移除当前Animator回调对象
        removeAnimationCallback();
        
        //一堆状态的重置
        ...
        mRunning = false;
        mStarted = false;
        mStartListenersCalled = false;
        mLastFrameTime = -1;
        mFirstFrameTime = -1;
        mStartTime = -1;
        if (notify && mListeners != null) {
            ArrayList<AnimatorListener> tmpListeners =
                    (ArrayList<AnimatorListener>) mListeners.clone();
            int numListeners = tmpListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                //回调所有注册的AnimatorListener的onAnimationEnd方法
                tmpListeners.get(i).onAnimationEnd(this, mReversing);
            }
        }
        ...
    }

3.1、cancel()动画

cancel()方法流程比较简单,源码如下:

@Override
    public void cancel() {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        if (mAnimationEndRequested) {
            return;
        }
        if ((mStarted || mRunning) && mListeners != null) {
            if (!mRunning) {
                // 如果尚未运行,监听器的onAnimationStart不会调用,先通知它们。
                notifyStartListeners();
            }
            ArrayList<AnimatorListener> tmpListeners =
                    (ArrayList<AnimatorListener>) mListeners.clone();
            for (AnimatorListener listener : tmpListeners) {
                //通知动画监听器onAnimationCancel
                listener.onAnimationCancel(this);
            }
        }
        
        //执行取消动画
        endAnimation();
    }

cancel()取消动画的时序图:

3.2、end()动画

 end()方法比起cancel()方法没有那么多状态位的复位,如果动画尚未启动,先启动动画;并且直接将动画执行到终点最后一帧,再结束动画。

@Override
    public void end() {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        if (!mRunning) {
            // 如果动画还没有开始的特殊情况; 准备好结束
            startAnimation();
            mStarted = true;
        } else if (!mInitialized) {
            initAnimation();
        }
        
        //将动画结束在最后一帧,反转动画则是起始位置
        animateValue(shouldPlayBackward(mRepeatCount, mReversing) ? 0f : 1f);
        
        //结束动画
        endAnimation();
    }

 end()结束动画的时序图:

简单的理解就是动画运行过程中调用cancel()方法直接在当前画面终止动画,而end()方法终止动画会让动画停留在最后一帧并结束动画。

4、动画的暂停和继续

改变动画执行状态的方法已经看了三个:start()、cancel()、end(),还有两个:pause()、resume(),分别用来暂停动画和继续动画。当Activity界面生命周期发生变化的时候,相应的应该处理动画的播放状态。举个例子:界面再后台的时候,动画应该暂停;界面切换到前台,动画再继续播放。

4.1、暂停动画pause()

pause()暂停动画的方法中,仅涉及一些状态的切换。并没有在该方法中将当前ValueAnimator动画从AnimationHandler中移除。

@Override
    public void pause() {
        boolean previouslyPaused = mPaused;
        //回调AnimatorPauseListener监听器 onAnimationPause
        super.pause();
        if (!previouslyPaused && mPaused) {
            mPauseTime = -1;
            mResumed = false;
        }
    }

让动画暂停的生效的其实是在动画执行的doAnimationFrame(long frameTime)方法中,如果判断了动画mPaused暂停状态,那么就将当前AnimationFrameCallback回调从AnimationHandler中移除。

public final boolean doAnimationFrame(long frameTime) {
        ...
        // 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);
            }
        }
        ...
    }

4.2、继续动画resume()

再来看看resume()继续播放动画的方法,该方法和start()方法中的一样,调用addAnimationCallback(long delay)向AnimationHandler中注册AnimationFrameCallback回调开启监听。

@Override
    public void resume() {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be resumed from the same " +
                    "thread that the animator was started on");
        }
        if (mPaused && !mResumed) {
            mResumed = true;
            if (mPauseTime > 0) {
                addAnimationCallback(0);
            }
        }
        super.resume();
    }

在Animator父类resume()方法中设置通用状态,及回调AnimatorPauseListener监听器的onAnimationResume(Animator animation)方法:

public void resume() {
        if (mPaused) {
            mPaused = false;
            if (mPauseListeners != null) {
                ArrayList<AnimatorPauseListener> tmpListeners =
                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
                int numListeners = tmpListeners.size();
                for (int i = 0; i < numListeners; ++i) {
                    tmpListeners.get(i).onAnimationResume(this);
                }
            }
        }
    }

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w