想必大家在做日常需求的时候,或多或少都有做过动画效果,借助的当然就是我们今天的主角:属性动画。对属性动画还不熟悉的小伙伴可以先去阅读下郭霖的文章,教科书级别的讲解啊哈哈,附上博客地址:https://blog.csdn.net/guolin_blog/article/details/43536355。好了,话不多说,下面我带领大家一起从源码的角度分析下属性动画。
通常,一个简单的动画,我们会这么写:
ObjectAnimator animator = ObjectAnimator.ofFloat(mTvTest, TextView.TRANSLATION_X, 0, 100);
animator.setDuration(500);
animator.start();
上述代码简单描述就是我们要对mTvTest控件的translationX进行操作,在500毫秒的时间,由0变为100。我们跟进去ObjectAnimator的ofFloat方法看下:
#ObjectAnimator
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
float... values) {
ObjectAnimator anim = new ObjectAnimator(target, property);
anim.setFloatValues(values);
return anim;
}
可以看到,在ObjectAnimator的ofFloat方法中,直接new了一个ObjectAnimator对象,最后将这个anim return掉。在ObjectAnimator对象的构造方法中执行了什么操作呢?我们跟进去:
private <T> ObjectAnimator(T target, Property<T, ?> property) {
setTarget(target);
setProperty(property);
}
ObjectAnimator的构造方法很简单,直接调用了setTarget和setProperty方法,完成mTarget和mProperty的赋值,代码如下:
@Override
public void setTarget(@Nullable Object target) {
final Object oldTarget = getTarget();
if (oldTarget != target) {
if (isStarted()) {
cancel();
}
//mTarget赋值
mTarget = target == null ? null : new WeakReference<Object>(target);
// New target should cause re-initialization prior to starting
mInitialized = false;
}
}
public void setProperty(@NonNull Property property) {
//代码有所删减,完成 mProperty赋值
if (mProperty != null) {
mPropertyName = property.getName();
}
mProperty = property;
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
好了我们回过头继续看ObjectAnimator的ofFloat方法,ObjectAnimator对象new完之后,接着就调用了anim的setFloatValues方法,将动画的start值和end值传入,我们跟进去看下:
#ObjectAnimator
@Override
public void setFloatValues(float... values) {
if (mValues == null || mValues.length == 0) {
//1、mProperty刚刚在构造方法中完成赋值,这里mProperty != null
if (mProperty != null) {
//2、调用setValues方法,对mValues进行赋值操作
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
}
} else {
super.setFloatValues(values);
}
}
在2处调用到了PropertyValuesHolder.ofFloat方法,将mProperty和values作为参数传入,我们跟进去看下:
#PropertyValuesHolder
public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
return new FloatPropertyValuesHolder(property, values);
}
可以看到,在PropertyValuesHolder的ofFloat方法中直接return了一个FloatPropertyValuesHolder对象,然后2处调用setValues方法,将该对象赋值给mValues。我们跟进去FloatPropertyValuesHolder的构造方法看下:
#FloatPropertyValuesHolder extends PropertyValuesHolder
public FloatPropertyValuesHolder(Property property, float... values) {
//1、调用super完成mProperty属性赋值
super(property);
//2、调用setFloatValues方法设置动画的起始值和结束值
setFloatValues(values);
if (property instanceof FloatProperty) {
mFloatProperty = (FloatProperty) mProperty;
}
}
我们跟进去2处的setFloatValues方法看下它是怎么设置动画的起始值和结束值的:
#FloatPropertyValuesHolder
@Override
public void setFloatValues(float... values) {
//1、调用super也就是PropertyValuesHolder类
super.setFloatValues(values);
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}
我们跟进去1处super.setFloatValues方法看下:
#PropertyValuesHolder
public void setFloatValues(float... values) {
mValueType = float.class;
//重点
mKeyframes = KeyframeSet.ofFloat(values);
}
接着跟KeyframeSet.ofFloat方法:
#KeyframeSet
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
//1、首先获取values的length,例如我们ObjectAnimator.ofFloat设置的 0, 100, 400;那么这里获取到的就是length就是3
int numKeyframes = values.length;
//2、创建keyframes数组,用来存放value
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
//3、如果这里我们只传入了一个动画的结束值,则默认添加起始值为0
if (numKeyframes == 1) {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
if (Float.isNaN(values[0])) {
badValue = true;
}
} else {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
//遍历values,将动画各个阶段设置的值包装成FloatKeyframe对象,存放在keyframes数组中
for (int i = 1; i < numKeyframes; ++i) {
keyframes[i] =
(FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
if (Float.isNaN(values[i])) {
badValue = true;
}
}
}
if (badValue) {
Log.w("Animator", "Bad value (NaN) in float animator");
}
return new FloatKeyframeSet(keyframes);
}
这下终于让我找到了吧!可以看到属性动画的起始值和结束值是存放在FloatKeyframeSet对象中的mKeyframes数组中啊啊啊。
好了,截止到现在,我们终于把ObjectAnimator.ofFloat方法分析完毕了,ObjectAnimator的setDuration方法中就是完成了mDuration的赋值,如果我们不调用setDuration方法的话,则默认动画时间为300毫秒,这里我就带领大家跟进去看了,大家有兴趣的话可以翻看源码看一下。接下来要做什么呢?那肯定就是animator.start()方法啦,各位老司机坐稳,要开车啦!我们跟进去animator.start()方法看下:
#ObjectAnimator
@Override
public void start() {
AnimationHandler.getInstance().autoCancelBasedOn(this);
if (DBG) {
Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
for (int i = 0; i < mValues.length; ++i) {
PropertyValuesHolder pvh = mValues[i];
Log.d(LOG_TAG, " Values[" + i + "]: " +
pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
pvh.mKeyframes.getValue(1));
}
}
//重点
super.start();
}
因为ObjectAnimator是继承自ValueAnimator,所以我们跟进去ValueAnimator的start()方法看下:
#ValueAnimator
@Override
public void start() {
start(false);
}
接着跟:
#ValueAnimator
private void start(boolean playBackwards) {
//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);
}
}
}
为了便于大家阅读,代码有所删减,我们跟进去1处的addAnimationCallback方法看下:
#ValueAnimator
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
这里首先调用了getAnimationHandler方法获取到AnimationHandler对象,然后调用AnimationHandler对象的addAnimationFrameCallback方法,将当前ObjectAnimator对象this传入。我们首先来看下getAnimationHandler方法:
public AnimationHandler getAnimationHandler() {
return AnimationHandler.getInstance();
}
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
接着我们跟进去AnimationHandler对象的addAnimationFrameCallback方法看下:
/**
* Register to get a callback on the next frame after the delay.
*/
#AnimationHandler
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
//1、mAnimationCallbacks是一个ArrayList集合,用来存储动画的回调
//起初mAnimationCallbacks.size() == 0,会调用MyFrameCallbackProvider的postFrameCallback方法,
//将mFrameCallback作为callback参数传入,这里涉及到Choreographer(编舞者),这样16.6毫秒后系统发出
//下一次脉冲信号时,会回调mFrameCallback的doFrame方法,我们就是在mFrameCallback的doFrame方法中完成动画操作的。
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
//2、若mAnimationCallbacks中不包含当前callback,则将当前callback add到mAnimationCallbacks集合中
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
上述代码中的1和2处我都做了标注,这里1处涉及到Choreographer系列操作,代码会有点多,不想看的小伙伴可以略过这一小节,直接往下看mFrameCallback的doFrame回调哈哈。我们先跟进去1处的getProvider方法看下:
#AnimationHandler
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
可以看到getProvider方法中return了MyFrameCallbackProvider对象。好了,我们跟进去MyFrameCallbackProvider对象的postFrameCallback方法看下:
#MyFrameCallbackProvider
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
在MyFrameCallbackProvider对象的postFrameCallback方法中直接调用到mChoreographer.postFrameCallback,我们接着跟:
#Choreographer
public void postFrameCallback(FrameCallback callback) {
postFrameCallbackDelayed(callback, 0);
}
--->
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
//重点
postCallbackDelayedInternal(CALLBACK_ANIMATION,
callback, FRAME_CALLBACK_TOKEN, delayMillis);
}
--->
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
//注意这里传入的delayMillis为0,即dueTime=now
final long dueTime = now + delayMillis;
//重点,将动画回调actiion封装成CallbackRecord对象,添加到mCallbackQueues对应的CallbackQueue中,内部通过单链表实现
//注意这里传入的callbackType为1,token为FRAME_CALLBACK_TOKEN
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);
}
}
}
--->
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
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()) {
//重点 如果在UI线程,则直接执行scheduleVsyncLocked方法,
//else 通过mHandler切换到UI线程再执行scheduleVsyncLocked方法
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
我们跟进去scheduleVsyncLocked方法看下:
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
mDisplayEventReceiver是个什么东西?我们看下它的声明:
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
我们跟进去FrameDisplayEventReceiver的scheduleVsync方法看下:
#DisplayEventReceiver
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);
}
}
让我们瞅瞅nativeScheduleVsync方法,看名字貌似是native方法:
@FastNative
private static native void nativeScheduleVsync(long receiverPtr);
再往下我们就不跟了,这里大家需要知道,我们在这里注册后,16.6毫秒系统发出下一次Vsync脉冲信号时会回调FrameDisplayEventReceiver对象的onVsync方法,我们跟进去看下:
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
FrameDisplayEventReceiver类的代码不多,我索性就都贴出来了,为了方便大家阅读,onVsync方法中的代码有所删减。可以看到,在onVsync方法中通过mHandler发送了一条异步消息,什么叫异步消息?这里就涉及到handler同步屏障相关的知识了,大家有兴趣的话可以去了解下,这里可以简单理解成优先级比较高的消息,会优先处理。注意Message.obtain方法的第二个参数为this,即设置了message的callback为当前FrameDisplayEventReceiver对象this,后续会直接走到FrameDisplayEventReceiver对象的run方法,我们可以看到,在run方法中直接调用到doFrame方法,我们跟进去看下:
#Choreographer
void doFrame(long frameTimeNanos, int frame) {
//一系列校验工作
...
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
//重点!!!
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took "
+ (endNanos - startNanos) * 0.000001f + " ms, latency "
+ (startNanos - frameTimeNanos) * 0.000001f + " ms.");
}
}
我们跟进去doCallbacks方法看下:
void doCallbacks(int callbackType, long frameTimeNanos) {
//我们前面提到过,属性动画传过来的callback就是封装在CallbackRecord中
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
for (CallbackRecord c = callbacks; c != null; c = c.next) {
//重点,遍历callbacks单链表,处理所有的动画回调,
//因为我们在app中不止设置一处动画,我们设置的所有动画都按照顺序存放在这个单链表中
//调用CallbackRecord的run方法
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
我们接着跟进去CallbackRecord的run方法:
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
public Object action; // Runnable or FrameCallback
public Object token;
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
可以看到在CallbackRecord对象的run方法中根据token进行判断,不知道大家还记不记得,我上面提到过,我们属性动画设置的token为FRAME_CALLBACK_TOKEN,所以就会走进if条件里面,执行((FrameCallback)action).doFrame方法,而action就是我们属性动画调用mChoreographer是传过来的mFrameCallback啊啊啊啊啊,这一连串操作。接下来肯定回到mFrameCallback的doFrame方法中了啊啊啊啊啊!!!
我们回去看下mFrameCallback的doFrame方法中,接着属性动画分析:
#AnimationHandler
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
//1、重点
doAnimationFrame(getProvider().getFrameTime());
//2、同样重点,这里就是动画连续的根源,只要mAnimationCallbacks.size() > 0,就继续将mFrameCallback进行注册,那么,下一帧脉冲信号到来就又会回调到该doFrame方法,执行1处操作。
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
在这里我们先来分析下2处,2处已经标注的很清晰了,这里就是动画连续的根源,只要mAnimationCallbacks.size() > 0,就继续将mFrameCallback进行注册,那么,下一帧脉冲信号到来就又会回调到该doFrame方法,执行1处操作。看到这里我们大家大胆猜想下,动画是怎么停止的呢?当然是将该动画的callback从mAnimationCallbacks中移除啦。到底是不是这样子实现的呢?我们后续会揭晓哈哈。我们跟进去1处看下:
#AnimationHandler
private void doAnimationFrame(long frameTime) {
long currentTime = SystemClock.uptimeMillis();
final int size = mAnimationCallbacks.size();
//遍历操作
for (int i = 0; i < size; i++) {
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
if (isCallbackDue(callback, currentTime)) {
//1、重点!!!
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
//2、清除mAnimationCallbacks中的无用callback
cleanUpList();
}
我们先来看下2处,cleanUpList方法中做了清除mAnimationCallbacks中的无用callback操作。其实我们当前属性动画结束的时候会将mAnimationCallbacks中相关的callback直接置为null,cleanUpList方法中会对mAnimationCallbacks进行遍历操作,将callback为null的callback直接remove掉,这样子当下次脉冲信号到来时只会处理其他正在执行的动画,当前动画就结束了。
我们跟进去1处看下,不知道小伙伴还记不记得1处的callback是什么?1处的callback就是我们之前传入的ObjectAnimator对象,so我们跟进去ObjectAnimator的doAnimationFrame方法中看下,ObjectAnimator类中没有doAnimationFrame方法,我们跟进去它的父类ValueAnimator中看下
#ValueAnimator
public final boolean doAnimationFrame(long frameTime) {
final long currentTime = Math.max(frameTime, mStartTime);
//1、重点!!!
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
//2、如果当前动画执行完毕,则调用endAnimation方法,后续就是我们上面刚提到的,
//将mAnimationCallbacks中相关的callback直接置为null
endAnimation();
}
return finished;
}
我们跟进去1处的animateBasedOnTime方法中看下:
#ValueAnimator
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
float currentIterationFraction = getCurrentIterationFraction(
mOverallFraction, mReversing);
//重点!!!
animateValue(currentIterationFraction);
}
return done;
}
由于我们当前是ObjectAnimator对象,而ObjectAnimator类对ValueAnimator类中的animateValue方法进行了复写,所以会调用到ObjectAnimator类的animateValue方法,我们跟进去看下:
#ObjectAnimator
@CallSuper
@Override
void animateValue(float fraction) {
final Object target = getTarget();
if (mTarget != null && target == null) {
// We lost the target reference, cancel and clean up. Note: we allow null target if the
/// target has never been set.
cancel();
return;
}
//1、重点,调用super.animateValue方法
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//2、重点
mValues[i].setAnimatedValue(target);
}
}
简单来讲,1处最终只是设置了当前时间点对应的动画数值,2处调用setAnimatedValue方法最终才会导致View的重绘,也就是invalidate方法的调用。我们先看下1处:
#ValueAnimator
@CallSuper
void animateValue(float fraction) {
//1、如果我们设置了插值器,则会回调我们插值器的getInterpolation方法获取进度,
//如果我们没有设置插值器,则使用默认的插值器获取动画进度
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//2、重点 这里会回调的FloatPropertyValuesHolder对象的calculateValue方法,将动画当前的进度传入
mValues[i].calculateValue(fraction);
}
//3、如果我们在外面设置了动画监听器,则会回调动画监听器的onAnimationUpdate方法,有没有很熟悉哈哈
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
我们跟进去FloatPropertyValuesHolder对象的calculateValue方法看下:
#FloatPropertyValuesHolder
@Override
void calculateValue(float fraction) {
mFloatAnimatedValue = mFloatKeyframes.getFloatValue(fraction);
}
这里mFloatKeyframes为FloatKeyframeSet对象,我们之前设置动画起始值和结束值的时候对它进行了赋值,我们跟进去FloatKeyframeSet的getFloatValue方法看下:
#FloatKeyframeSet
@Override
public float getFloatValue(float fraction) {
//代码有所删减,这里处理了fraction<=0和fraction>=1的情况
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
for (int i = 1; i < mNumKeyframes; ++i) {
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
if (fraction < nextKeyframe.getFraction()) {
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
float prevValue = prevKeyframe.getFloatValue();
float nextValue = nextKeyframe.getFloatValue();
// Apply interpolator on the proportional duration.
if (interpolator != null) {
intervalFraction = interpolator.getInterpolation(intervalFraction);
}
//重点!!!如果我们在外面设置了估值器,即mEvaluator!=null,则会回调我们设置估值器
//的evaluate方法获取到当前时间点对应的动画数值,否则按照以下计算当前时间点对应的动画数值!
return mEvaluator == null ?
prevValue + intervalFraction * (nextValue - prevValue) :
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
floatValue();
}
prevKeyframe = nextKeyframe;
}
// shouldn't get here
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
}
可以看到在getFloatValue方法中主要是计算当前时间点对应的动画数值,然后将该动画数值return掉,赋值给FloatPropertyValuesHolder对象的mFloatAnimatedValue字段。
好了,我们回过头回到ObjectAnimator类的animateValue方法中,1处的super完成后,我们看下2处的setAnimatedValue方法,2处的mValues[i]其实是我们之前设置的FloatPropertyValuesHolder对象,so我们就来到FloatPropertyValuesHolder对象的setAnimatedValue方法中:
@Override
void setAnimatedValue(Object target) {
//1、重点!mFloatProperty就是我们外部调用传入的TextView.TRANSLATION_X,
//所以这里会回调TextView.TRANSLATION_X的setValue方法,
//将我们所要操作的控件(这里指mTvTest)和当前时间点对应的动画进度作为参数传入
if (mFloatProperty != null) {
mFloatProperty.setValue(target, mFloatAnimatedValue);
return;
}
if (mProperty != null) {
mProperty.set(target, mFloatAnimatedValue);
return;
}
if (mJniSetter != 0) {
nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
return;
}
if (mSetter != null) {
try {
mTmpValueArray[0] = mFloatAnimatedValue;
mSetter.invoke(target, mTmpValueArray);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
Log.e("PropertyValuesHolder", e.toString());
}
}
}
哈哈现在有点眉目了吧,1处mFloatProperty就是我们外部调用传入的TextView.TRANSLATION_X,所以这里会回调TextView.TRANSLATION_X的setValue方法,将我们所要操作的控件(这里指mTvTest)和当前时间点对应的动画值作为参数传入。那还不赶紧跟进去TextView.TRANSLATION_X看下:
#View
public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") {
@Override
public void setValue(View object, float value) {
object.setTranslationX(value);
}
@Override
public Float get(View object) {
return object.getTranslationX();
}
};
简单明了,TRANSLATION_X的setValue方法中直接调用 object.setTranslationX方法,也就是当前动画所要操作的控件的setTranslationX方法,将当前时间点对应的动画值作为参数传入(这里是调用到mTvTest控件的setTranslationX方法)。在View的setTranslationX方法内部会调用invalidate方法,从而完成View的重绘操作。
好了,到此为止,属性动画源码相关的解析就结束了,欢迎大家一起探讨呀!
网友评论