转载请注明出处: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节中可以看到,想要让动画按照我们预期的行为来执行,需要做的就是找到合适的函数。