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 就分析完了。不同的版本这个机制有差别,这个就不分析了。