ValueAnimator 是属性动画的管理类,其主要是对变量值进行回调产出,然后我们利用这个回调值做一些动画效果。一般用法如下:
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 1000,1); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (Integer) animation.getAnimatedValue(); RelativeLayout.LayoutParams layoutParams=(RelativeLayout.LayoutParams)button.getLayoutParams(); layoutParams.setMargins(value, 0, 0, 0); button.setLayoutParams(layoutParams); } }); valueAnimator.setDuration(4000); valueAnimator.setRepeatCount(10); valueAnimator.start();其实这种源码分析主要分析start方法即可,这个是落脚点,其余的主页是设置值用的。 playBackwards 是否需要反转来产生动画效果。这里默认是false。.
@Override public void start() { start(false); } private void start(boolean playBackwards) { //这里检查线程变量Loop是否存在。一般情况下如果主线程操作start肯定是存在。如果非主线程操作的话需要进行Loop.prepare(),其实吧这种操作也可以在start里面做,但是目前需要自己去操作。有时候些代码就是这样,库做一部分工作,使用者做一部分工作。大家协调合作。 if (Looper.myLooper() == null) { throw new AndroidRuntimeException("Animators may only be run on Looper threads"); } mReversing = playBackwards; mPlayingBackwards = playBackwards; //非repeat的情况,这个逻辑不会走。 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(); }最后要跳到这个主要方法,中间的不重要细节忽略掉了。
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. //如果准备执行的动画的ValueAnimator 存在 while (mPendingAnimations.size() > 0) { // 享元模式,也称为克隆模式。 ArrayList<ValueAnimator> pendingCopy = (ArrayList<ValueAnimator>) mPendingAnimations.clone(); //清空mPendingAnimations 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 //后续处理需要延迟的动画。如果时间未到会重新调用 scheduleAnimation();进行下次调度。那么 //我们的逻辑放在startAnimation(this)上面吧。 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); //此处doAnimationFrame 进行了动画的过程处理。 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(); } }接下来看下ValueAnimator的doAnimationFrame。大家不要混淆了AnimationHander的同名方法, 感觉这个命名最好还是不一样为好,容易让人混淆。
```java final boolean doAnimationFrame(long frameTime) { if (mPlayingState == STOPPED) { mPlayingState = RUNNING; if (mSeekTime < 0) { mStartTime = frameTime; } else { mStartTime = frameTime - mSeekTime; // Now that we're playing, reset the seek time mSeekTime = -1; } } 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); } } // 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 (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; } animateValue(fraction); break; } return done; }这个实际的计算插值的过程。
void animateValue(float fraction) { fraction = mInterpolator.getInterpolation(fraction); mCurrentFraction = fraction; int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { //此处已经完成了赋值,后续我们getAnimatedValue() 得到计算后的值。 mValues[i].calculateValue(fraction); } if (mUpdateListeners != null) { int numListeners = mUpdateListeners.size(); for (int i = 0; i < numListeners; ++i) { //回调后我们通过getAnimatedValue() 来得到相应的插值。 mUpdateListeners.get(i).onAnimationUpdate(this); } } }整个ValueAnimator 就分析完了。不同的版本这个机制有差别,这个就不分析了。