Android 动画animation 深入分析

来源:互联网 发布:软件管理生产论文 编辑:程序博客网 时间:2024/05/03 16:27

转载请注明出处:http://blog.csdn.net/farmer_cc/article/details/18259117

Android 动画animation 深入分析

前言:本文试图通过分析动画流程,来理解android动画系统的设计与实现,学习动画的基本原则,最终希望能够指导动画的设计。


0 本文中用到的一些类图



1 view animation 

调用方法:view.startAnimation(animation);

    public void startAnimation(Animation animation) {        animation.setStartTime(Animation.START_ON_FIRST_FRAME);        setAnimation(animation);        invalidateParentCaches();        invalidate(true);    }
在invalidate(ture);中

            if (p != null && ai != null) {                final Rect r = ai.mTmpInvalRect;                r.set(0, 0, mRight - mLeft, mBottom - mTop);                // Don't call invalidate -- we don't want to internally scroll                // our own bounds                p.invalidateChild(this, r);            }

即调用parent的invalidateChild,


假定父控件即为ViewRootImpl;

public final class ViewRootImpl implements ViewParent;

    @Override    public void invalidateChild(View child, Rect dirty) {        invalidateChildInParent(null, dirty);    }    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {        //...省略一堆判断条件,最终调用        if (!mWillDrawSoon && (intersected || mIsAnimating)) {            scheduleTraversals();        }        return null;    }
    void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().postSyncBarrier();            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);            scheduleConsumeBatchedInput();        }    }
其中mTraversalBarrier = mHandler.getLooper().postSyncBarrier();是设置同步障碍(syncBarrier),当looper中的消息队列执行到barrier 后,会暂停执行,只有当barrier 被释放mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); 后消息队列才能继续执行。

    Choreographer mChoreographer; 是动画系统中的核心组织者, 负责统一调度。后面详细说。

    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();    final class TraversalRunnable implements Runnable {        @Override        public void run() {            doTraversal();        }    }

    void doTraversal() {        performTraversals();    }
perform 待补充

    final class ConsumeBatchedInputRunnable implements Runnable {        @Override        public void run() {            doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());        }    }    final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =            new ConsumeBatchedInputRunnable();
doConsume 待补充



2 属性动画aninmator

valueAnimator.start();

    private void start(boolean playBackwards) {        if (Looper.myLooper() == null) {            throw new AndroidRuntimeException("Animators may only be run on Looper threads");        }        AnimationHandler animationHandler = getOrCreateAnimationHandler();        animationHandler.mPendingAnimations.add(this);        if (mStartDelay == 0) {            // This sets the initial value of the animation, prior to actually starting it running            setCurrentPlayTime(0);            mPlayingState = STOPPED;            mRunning = true;            notifyStartListeners();        }        animationHandler.start();    }
这里会检查调用线程必须是Looper线程,如果是view相关的属性动画,还必须是UI 线程。

得到AnimationHandle 并把自己加入到PendingAnimations  的list中.

getOrCreateAnimationHandler();
    protected static ThreadLocal<AnimationHandler> sAnimationHandler =            new ThreadLocal<AnimationHandler>()    protected static class AnimationHandler implements Runnable {        // The per-thread list of all active animations        /** @hide */        protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();        // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations        private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();        // The per-thread set of animations to be started on the next animation frame        /** @hide */        protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();        /**         * Internal per-thread collections used to avoid set collisions as animations start and end         * while being processed.         * @hide         */        protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();        private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();        private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();        private final Choreographer mChoreographer;        private boolean mAnimationScheduled;}

AnimationHandler 就是一个runnable, 注意成员变量中的多个animator 的list 以及重要的mChoreographer = Choreographer.getInstance();

mChoreographer 也是一个threadlocal的变量。

在animationHandler.start() 中

        public void start() {            scheduleAnimation();        }        private void scheduleAnimation() {            if (!mAnimationScheduled) {                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);                mAnimationScheduled = true;            }        }
this 是runnable 即把animationHandler自己添加添加到mChoreographer 的队列中。

    public void postCallback(int callbackType, Runnable action, Object token) {        postCallbackDelayed(callbackType, action, token, 0);    }    public void postCallbackDelayed(int callbackType,            Runnable action, Object token, long delayMillis) {        postCallbackDelayedInternal(callbackType, action, 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) {                scheduleFrameLocked(now);            } else {                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);                msg.arg1 = callbackType;                msg.setAsynchronous(true);                mHandler.sendMessageAtTime(msg, dueTime);            }        }    }
传入的delay为0, 即调用scheduleFrameLocked(now);

    private void scheduleFrameLocked(long now) {        if (!mFrameScheduled) {            mFrameScheduled = true;            if (USE_VSYNC) {                if (DEBUG) {                    Log.d(TAG, "Scheduling next frame on vsync.");                }                // If running on the Looper thread, then schedule the vsync immediately,                // otherwise post a message to schedule the vsync from the UI thread                // as soon as possible.                if (isRunningOnLooperThreadLocked()) {                    scheduleVsyncLocked();                } else {                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);                    msg.setAsynchronous(true);                    mHandler.sendMessageAtFrontOfQueue(msg);                }            } else {                final long nextFrameTime = Math.max(                        mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);                if (DEBUG) {                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");                }                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);                msg.setAsynchronous(true);                mHandler.sendMessageAtTime(msg, nextFrameTime);            }        }    }
    private static final boolean USE_VSYNC = SystemProperties.getBoolean(            "debug.choreographer.vsync", true);
USE_VSYNC 默认是true;    

    private boolean isRunningOnLooperThreadLocked() {        return Looper.myLooper() == mLooper;    }
检查当前looper和mChoreographer的looper是否一致。一般情况是一致的。就会调用scheduleVsyncLocked();

    private void scheduleVsyncLocked() {        mDisplayEventReceiver.scheduleVsync();    }
    public void scheduleVsync() {        if (mReceiverPtr == 0) {            Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "                    + "receiver has already been disposed.");        } else {            nativeScheduleVsync(mReceiverPtr);        }    }
到了native 暂时先不涉及。

回头来看animationHandler 的run()。 前面提到animationHandler把自己添加到mChoreographer,当被调用时,调用run方法。

        // Called by the Choreographer.        @Override        public void run() {            mAnimationScheduled = false;            doAnimationFrame(mChoreographer.getFrameTime());        }

    public long getFrameTime() {        return getFrameTimeNanos() / NANOS_PER_MS;    }    public long getFrameTimeNanos() {        synchronized (mLock) {            if (!mCallbacksRunning) {                throw new IllegalStateException("This method must only be called as "                        + "part of a callback while a frame is in progress.");            }            return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();        }    }
doAnimationFrame()总结就是

1.遍历pending list动画,如果delay为0 则调用start,不为0,加入delay list;

2.遍历delay list, 根据frametime计算是继续delay还是ready可以播放,若是ready,则加入到ready list中;

3 遍历ready list,调用start ;

4,遍历所有animation,根据frametime计算动画是否要结束,如果可以结束,则加入到ending list中;

5,遍历ending list, 调用end;

6, 如果有列表中仍然有动画,则继续scheduleAnimation;

        private void doAnimationFrame(long 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();            }            // 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();            }        }

在animationFrame() 中根据当前状态,并且计算fraction,调用animateValue();

    boolean animationFrame(long currentTime) {        boolean done = false;        switch (mPlayingState) {        case RUNNING:        case SEEKED:            //省略计算fraction的代码            animateValue(fraction);            break;        }        return done;    }
通过mInterpolator.getInterpolation计算fraction;@Interpolator 

根据fraction计算内部所有value,如果有updateListener,调用之。

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

3. 插值器

从上面的介绍可以看到,Interpolator的关键是getInterpolation();

在ValueAnimator.animationFrame()中可以看到, 传递给Interpolator 的fraction是在[0,1] 值域范围。

            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;            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;                } else {                    done = true;                    fraction = Math.min(fraction, 1.0f);                }            }            if (mPlayingBackwards) {                fraction = 1f - fraction;            }

所以设计Interpolator 就是设计一个输入[0,1] 的函数。

先参观一下系统的几个Interpolator。

3.1 AccelerateDecelerateInterpolator

cos(t+1)Pi /2 +0.5f

从图可以看到,先加速后减速,病最终到达结束位置。


public class AccelerateDecelerateInterpolator implements Interpolator {    public float getInterpolation(float input) {        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;    }}


3.2 AccelerateInterpolator

如果factor=1 则函数为x^2

否则函数为x^a (a 是参数)

默认函数式x^2

如图示,逐渐加速到结束位置。

public class AccelerateInterpolator implements Interpolator {    private final float mFactor;    private final double mDoubleFactor;    public AccelerateInterpolator() {        mFactor = 1.0f;        mDoubleFactor = 2.0;    }        /**     * Constructor     *      * @param factor Degree to which the animation should be eased. Seting     *        factor to 1.0f produces a y=x^2 parabola. Increasing factor above     *        1.0f  exaggerates the ease-in effect (i.e., it starts even     *        slower and ends evens faster)     */    public AccelerateInterpolator(float factor) {        mFactor = factor;        mDoubleFactor = 2 * mFactor;    }     public float getInterpolation(float input) {        if (mFactor == 1.0f) {            return input * input;        } else {            return (float)Math.pow(input, mDoubleFactor);        }    }}



3.3 LinearInterpolator

线性的就是Y=X 没啥说的。



public class LinearInterpolator implements Interpolator {    public float getInterpolation(float input) {        return input;    }}


3.4 anticipateInterpolator  

函数是:x^2((a+1)x-a) 默认参数a=2 默认函数为x^2(3x-1)

如图示, 会先反方向执行一段,然后正向一直加速至结束位置。


public class AnticipateInterpolator implements Interpolator {    private final float mTension;    public AnticipateInterpolator() {        mTension = 2.0f;    }    /**     * @param tension Amount of anticipation. When tension equals 0.0f, there is     *                no anticipation and the interpolator becomes a simple     *                acceleration interpolator.     */    public AnticipateInterpolator(float tension) {        mTension = tension;    }    public float getInterpolation(float t) {        // a(t) = t * t * ((tension + 1) * t - tension)        return t * t * ((mTension + 1) * t - mTension);    }}



3.5 aniticipateOvershoot

是一个分段函数,默认参数a=3

2x*x[(2x*(a+1)-a)]     0<=x<=0.5

2(x-1)(x-1)[(2x-1)(a+1)+a]    0.5<x<=1

通过下图可以看到,动画会先反方向执行,然后向正方向逐渐加速,在快结束时逐渐减速,并超过预设的值,最后回到结束位置。


2x*x[(2x*(a+1)-a)]     0<=x<=0.5 的函数图



2(x-1)(x-1)[(2x-1)(a+1)+a]    0.5<x<=1的函数图

public class AnticipateOvershootInterpolator implements Interpolator {    private final float mTension;    public AnticipateOvershootInterpolator() {        mTension = 2.0f * 1.5f;    }    /**     * @param tension Amount of anticipation/overshoot. When tension equals 0.0f,     *                there is no anticipation/overshoot and the interpolator becomes     *                a simple acceleration/deceleration interpolator.     */    public AnticipateOvershootInterpolator(float tension) {        mTension = tension * 1.5f;    }    /**     * @param tension Amount of anticipation/overshoot. When tension equals 0.0f,     *                there is no anticipation/overshoot and the interpolator becomes     *                a simple acceleration/deceleration interpolator.     * @param extraTension Amount by which to multiply the tension. For instance,     *                     to get the same overshoot as an OvershootInterpolator with     *                     a tension of 2.0f, you would use an extraTension of 1.5f.     */    public AnticipateOvershootInterpolator(float tension, float extraTension) {        mTension = tension * extraTension;    }    private static float a(float t, float s) {        return t * t * ((s + 1) * t - s);    }    private static float o(float t, float s) {        return t * t * ((s + 1) * t + s);    }    public float getInterpolation(float t) {        // a(t, s) = t * t * ((s + 1) * t - s)        // o(t, s) = t * t * ((s + 1) * t + s)        // f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5        // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0        if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);        else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);    }}

4. 指导设计动画。

从第3节中可以看到,想要让动画按照我们预期的行为来执行,需要做的就是找到合适的函数。

画图使用http://www.fooplot.com/在线工具


9 0
原创粉丝点击