正文
Evaluator.evaluate(float fraction, Number startValue, Number endValue)
如果我们传入了
ObjectAnimator.ofFloat(animationView, "X", 0, 100, 200, 500);
我们传入 4 个值,那么我们的动画将分为 3 个部分
0 ~ 100 一个阶段, fraction 从 0.0 ~ 1.0;
startValue = 0,endValue =100
100 ~ 200 一个阶段, fraction 从 0.0 ~ 1.0;
startValue = 100,endValue =200
200 ~ 500 一个阶段, fraction 从 0.0 ~ 1.0;
startValue = 200,endValue =500
然后 FloatPropertyValuesHolder 创建部分完毕,一层一层向上返回。
(O__O "…,如果忘记这个部分在哪,可以往上翻去看看)
然后执行 ObjectAnimator.setValues() ,ObjectAnimator 直接调用了父类的 ValueAnimator.setValues()
public void setValues(PropertyValuesHolder... values) {
int numValues = values.length;
mValues = values;
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
PropertyValuesHolder valuesHolder = values[i];
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
然后我们看到 mValues 和 mValuesMap 赋值操作了。mValues 和 mValuesMap 持有的对象就是我们创建的 FloatPropertyValuesHolder
终于我们完成了 ObjectAnimator 创建过程的源代码追踪,总结如下
1. 创建 ObjectAnimator 对象,保存 target 和 propertyName
2. 根据传入的 values 创建一组关键帧。
3. 关键帧封装到 FloatPropertyValuesHolder 中。
4. FloatPropertyValuesHolder 交给 mValues 和 mValuesMap 持有
总结一下整个流程
animation_01.png
开启动画
这一步是整个属性动画中最麻烦的操作,一层一层的剥开源码,搞得我眼睛干涩,脾气暴躁一度想放弃。
所以先做个深呼吸~,准备迎接更虐心的源码追踪。
objectAnimator.start()
public void start() {
AnimationHandler.getInstance().autoCancelBasedOn(this);
……
super.start();
}
这里有两句关键代码,其他代码没有贴出来。第一句检测如果动画已经执行,则停止动画。
如果不理解,并不重要。因为第一次调用的时候,肯定没有动画在执行。等看完整个过程就明白这一句的意思了。
然后我们发现又双叒叕调用了父类的方法。
public void start() {
start(false);
}
然后加了一个
false
参数继续调用同名函数
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mReversing = playBackwards;
mSelfPulse = !mSuppressSelfPulseRequested;
…… 这里的代码此时不会执行,先省略
mStarted = true;
mPaused = false;
mRunning = false;
mAnimationEndRequested = false;
// Resets mLastFrameTime when start() is called, so that if the animation was running,
// calling start() would put the animation in the
// started-but-not-yet-reached-the-first-frame phase.
mLastFrameTime = -1;
mFirstFrameTime = -1;
mStartTime = -1;
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// If there's no start delay, init the animation and notify start listeners right away
// to be consistent with the previous behavior. Otherwise, postpone this until the first
// frame after the start delay.
startAnimation();
if (mSeekFraction == -1) {
// No seek, start at play time 0. Note that the reason we are not using fraction 0
// is because for animations with 0 duration, we want to be consistent with pre-N
// behavior: skip to the final value immediately.
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
start(boolean playBackwards) 方法比较长,仔细咀嚼改方法后,找到三个地方比较重要
1. addAnimationCallback(0)
2. startAnimation()
3. setCurrentPlayTime(0)/setCurrentFraction(mSeekFraction) 其实是一个方法,因为 setCurrentPlayTime 会调用 setCurrentFraction(mSeekFraction)
这三个地方『1』是最负责的一步,但是又是最重要的一步,再做一次深呼吸,然后准备跟下去!
addAnimationCallback(0)
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
这里一下子出现两个方法调用,先看下 getAnimationHandler()
public AnimationHandler getAnimationHandler() {
return AnimationHandler.getInstance();
}
好像是获取一个 AnimationHandler 对象。似乎还是一个单利
public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
private boolean mListDirty = false;
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
原来 AnimationHandler 用 ThreadLocal 保证每个线程只有一个实例。做到线程中单例。
然后看下 AnimationHandler.addAnimationFrameCallback()
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
执行动画的时候 mAnimationCallbacks.size() = 0 所以会执行(这里稍微留意一下传入的 callback)
getProvider().postFrameCallback(mFrameCallback)
看下 getProvider()
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
返回了一个 MyFrameCallbackProvider() 对象,而且改对象的构造方法并无特别之处。然后我们在看下 mFrameCallback 对象。
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
mFrameCallback 又是一个回调方法,而且 doFrame() 方法中好像有传入了自身。