想必大家在做日常需求的時(shí)候打肝,或多或少都有做過(guò)動(dòng)畫(huà)效果,借助的當(dāng)然就是我們今天的主角:屬性動(dòng)畫(huà)厌漂。對(duì)屬性動(dòng)畫(huà)還不熟悉的小伙伴可以先去閱讀下郭霖的文章哨啃,教科書(shū)級(jí)別的講解啊哈哈烧栋,附上博客地址:https://blog.csdn.net/guolin_blog/article/details/43536355。好了拳球,話不多說(shuō)审姓,下面我?guī)ьI(lǐng)大家一起從源碼的角度分析下屬性動(dòng)畫(huà)。
通常祝峻,一個(gè)簡(jiǎn)單的動(dòng)畫(huà)魔吐,我們會(huì)這么寫(xiě):
ObjectAnimator animator = ObjectAnimator.ofFloat(mTvTest, TextView.TRANSLATION_X, 0, 100);
animator.setDuration(500);
animator.start();
上述代碼簡(jiǎn)單描述就是我們要對(duì)mTvTest控件的translationX進(jìn)行操作,在500毫秒的時(shí)間莱找,由0變?yōu)?00酬姆。我們跟進(jìn)去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了一個(gè)ObjectAnimator對(duì)象轴踱,最后將這個(gè)anim return掉。在ObjectAnimator對(duì)象的構(gòu)造方法中執(zhí)行了什么操作呢谚赎?我們跟進(jìn)去:
private <T> ObjectAnimator(T target, Property<T, ?> property) {
setTarget(target);
setProperty(property);
}
ObjectAnimator的構(gòu)造方法很簡(jiǎn)單,直接調(diào)用了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;
}
好了我們回過(guò)頭繼續(xù)看ObjectAnimator的ofFloat方法棕所,ObjectAnimator對(duì)象new完之后闸盔,接著就調(diào)用了anim的setFloatValues方法,將動(dòng)畫(huà)的start值和end值傳入琳省,我們跟進(jìn)去看下:
#ObjectAnimator
@Override
public void setFloatValues(float... values) {
if (mValues == null || mValues.length == 0) {
//1迎吵、mProperty剛剛在構(gòu)造方法中完成賦值,這里mProperty != null
if (mProperty != null) {
//2针贬、調(diào)用setValues方法击费,對(duì)mValues進(jìn)行賦值操作
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
}
} else {
super.setFloatValues(values);
}
}
在2處調(diào)用到了PropertyValuesHolder.ofFloat方法,將mProperty和values作為參數(shù)傳入桦他,我們跟進(jìn)去看下:
#PropertyValuesHolder
public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
return new FloatPropertyValuesHolder(property, values);
}
可以看到蔫巩,在PropertyValuesHolder的ofFloat方法中直接return了一個(gè)FloatPropertyValuesHolder對(duì)象,然后2處調(diào)用setValues方法,將該對(duì)象賦值給mValues圆仔。我們跟進(jìn)去FloatPropertyValuesHolder的構(gòu)造方法看下:
#FloatPropertyValuesHolder extends PropertyValuesHolder
public FloatPropertyValuesHolder(Property property, float... values) {
//1垃瞧、調(diào)用super完成mProperty屬性賦值
super(property);
//2、調(diào)用setFloatValues方法設(shè)置動(dòng)畫(huà)的起始值和結(jié)束值
setFloatValues(values);
if (property instanceof FloatProperty) {
mFloatProperty = (FloatProperty) mProperty;
}
}
我們跟進(jìn)去2處的setFloatValues方法看下它是怎么設(shè)置動(dòng)畫(huà)的起始值和結(jié)束值的:
#FloatPropertyValuesHolder
@Override
public void setFloatValues(float... values) {
//1坪郭、調(diào)用super也就是PropertyValuesHolder類(lèi)
super.setFloatValues(values);
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}
我們跟進(jìn)去1處super.setFloatValues方法看下:
#PropertyValuesHolder
public void setFloatValues(float... values) {
mValueType = float.class;
//重點(diǎn)
mKeyframes = KeyframeSet.ofFloat(values);
}
接著跟KeyframeSet.ofFloat方法:
#KeyframeSet
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
//1个从、首先獲取values的length,例如我們ObjectAnimator.ofFloat設(shè)置的 0歪沃, 100嗦锐, 400;那么這里獲取到的就是length就是3
int numKeyframes = values.length;
//2绸罗、創(chuàng)建keyframes數(shù)組意推,用來(lái)存放value
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
//3、如果這里我們只傳入了一個(gè)動(dòng)畫(huà)的結(jié)束值珊蟀,則默認(rèn)添加起始值為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菊值,將動(dòng)畫(huà)各個(gè)階段設(shè)置的值包裝成FloatKeyframe對(duì)象,存放在keyframes數(shù)組中
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);
}
這下終于讓我找到了吧育灸!可以看到屬性動(dòng)畫(huà)的起始值和結(jié)束值是存放在FloatKeyframeSet對(duì)象中的mKeyframes數(shù)組中啊啊啊腻窒。
好了,截止到現(xiàn)在磅崭,我們終于把ObjectAnimator.ofFloat方法分析完畢了儿子,ObjectAnimator的setDuration方法中就是完成了mDuration的賦值,如果我們不調(diào)用setDuration方法的話砸喻,則默認(rèn)動(dòng)畫(huà)時(shí)間為300毫秒柔逼,這里我就帶領(lǐng)大家跟進(jìn)去看了,大家有興趣的話可以翻看源碼看一下割岛。接下來(lái)要做什么呢愉适?那肯定就是animator.start()方法啦,各位老司機(jī)坐穩(wěn)癣漆,要開(kāi)車(chē)?yán)参蹋∥覀兏M(jìn)去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));
}
}
//重點(diǎn)
super.start();
}
因?yàn)镺bjectAnimator是繼承自ValueAnimator,所以我們跟進(jìn)去ValueAnimator的start()方法看下:
#ValueAnimator
@Override
public void start() {
start(false);
}
接著跟:
#ValueAnimator
private void start(boolean playBackwards) {
//1惠爽、重點(diǎn)
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);
}
}
}
為了便于大家閱讀癌蓖,代碼有所刪減,我們跟進(jìn)去1處的addAnimationCallback方法看下:
#ValueAnimator
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
這里首先調(diào)用了getAnimationHandler方法獲取到AnimationHandler對(duì)象婚肆,然后調(diào)用AnimationHandler對(duì)象的addAnimationFrameCallback方法租副,將當(dāng)前ObjectAnimator對(duì)象this傳入。我們首先來(lái)看下getAnimationHandler方法:
public AnimationHandler getAnimationHandler() {
return AnimationHandler.getInstance();
}
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
接著我們跟進(jìn)去AnimationHandler對(duì)象的addAnimationFrameCallback方法看下:
/**
* Register to get a callback on the next frame after the delay.
*/
#AnimationHandler
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
//1较性、mAnimationCallbacks是一個(gè)ArrayList集合附井,用來(lái)存儲(chǔ)動(dòng)畫(huà)的回調(diào)
//起初mAnimationCallbacks.size() == 0讨越,會(huì)調(diào)用MyFrameCallbackProvider的postFrameCallback方法,
//將mFrameCallback作為callback參數(shù)傳入永毅,這里涉及到Choreographer(編舞者)把跨,這樣16.6毫秒后系統(tǒng)發(fā)出
//下一次脈沖信號(hào)時(shí),會(huì)回調(diào)mFrameCallback的doFrame方法沼死,我們就是在mFrameCallback的doFrame方法中完成動(dòng)畫(huà)操作的着逐。
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
//2、若mAnimationCallbacks中不包含當(dāng)前callback意蛀,則將當(dāng)前callback add到mAnimationCallbacks集合中
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
上述代碼中的1和2處我都做了標(biāo)注耸别,這里1處涉及到Choreographer系列操作,代碼會(huì)有點(diǎn)多县钥,不想看的小伙伴可以略過(guò)這一小節(jié)秀姐,直接往下看mFrameCallback的doFrame回調(diào)哈哈。我們先跟進(jìn)去1處的getProvider方法看下:
#AnimationHandler
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
可以看到getProvider方法中return了MyFrameCallbackProvider對(duì)象若贮。好了省有,我們跟進(jìn)去MyFrameCallbackProvider對(duì)象的postFrameCallback方法看下:
#MyFrameCallbackProvider
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
在MyFrameCallbackProvider對(duì)象的postFrameCallback方法中直接調(diào)用到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");
}
//重點(diǎn)
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;
//重點(diǎn)蠢沿,將動(dòng)畫(huà)回調(diào)actiion封裝成CallbackRecord對(duì)象,添加到mCallbackQueues對(duì)應(yīng)的CallbackQueue中匾效,內(nèi)部通過(guò)單鏈表實(shí)現(xiàn)
//注意這里傳入的callbackType為1舷蟀,token為FRAME_CALLBACK_TOKEN
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
//重點(diǎn)
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()) {
//重點(diǎn) 如果在UI線程,則直接執(zhí)行scheduleVsyncLocked方法面哼,
//else 通過(guò)mHandler切換到UI線程再執(zhí)行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);
}
}
}
我們跟進(jìn)去scheduleVsyncLocked方法看下:
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
mDisplayEventReceiver是個(gè)什么東西野宜?我們看下它的聲明:
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
我們跟進(jìn)去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 {
//重點(diǎn)
nativeScheduleVsync(mReceiverPtr);
}
}
讓我們瞅瞅nativeScheduleVsync方法,看名字貌似是native方法:
@FastNative
private static native void nativeScheduleVsync(long receiverPtr);
再往下我們就不跟了,這里大家需要知道魔策,我們?cè)谶@里注冊(cè)后匈子,16.6毫秒系統(tǒng)發(fā)出下一次Vsync脈沖信號(hào)時(shí)會(huì)回調(diào)FrameDisplayEventReceiver對(duì)象的onVsync方法,我們跟進(jìn)去看下:
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類(lèi)的代碼不多代乃,我索性就都貼出來(lái)了,為了方便大家閱讀仿粹,onVsync方法中的代碼有所刪減搁吓。可以看到吭历,在onVsync方法中通過(guò)mHandler發(fā)送了一條異步消息堕仔,什么叫異步消息?這里就涉及到handler同步屏障相關(guān)的知識(shí)了晌区,大家有興趣的話可以去了解下摩骨,這里可以簡(jiǎn)單理解成優(yōu)先級(jí)比較高的消息通贞,會(huì)優(yōu)先處理。注意Message.obtain方法的第二個(gè)參數(shù)為this恼五,即設(shè)置了message的callback為當(dāng)前FrameDisplayEventReceiver對(duì)象this昌罩,后續(xù)會(huì)直接走到FrameDisplayEventReceiver對(duì)象的run方法,我們可以看到灾馒,在run方法中直接調(diào)用到doFrame方法茎用,我們跟進(jìn)去看下:
#Choreographer
void doFrame(long frameTimeNanos, int frame) {
//一系列校驗(yàn)工作
...
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();
//重點(diǎn)!!!
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.");
}
}
我們跟進(jìn)去doCallbacks方法看下:
void doCallbacks(int callbackType, long frameTimeNanos) {
//我們前面提到過(guò),屬性動(dòng)畫(huà)傳過(guò)來(lái)的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) {
//重點(diǎn)睬罗,遍歷callbacks單鏈表轨功,處理所有的動(dòng)畫(huà)回調(diào),
//因?yàn)槲覀冊(cè)赼pp中不止設(shè)置一處動(dòng)畫(huà)容达,我們?cè)O(shè)置的所有動(dòng)畫(huà)都按照順序存放在這個(gè)單鏈表中
//調(diào)用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);
}
}
我們接著跟進(jìn)去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對(duì)象的run方法中根據(jù)token進(jìn)行判斷古涧,不知道大家還記不記得,我上面提到過(guò)花盐,我們屬性動(dòng)畫(huà)設(shè)置的token為FRAME_CALLBACK_TOKEN羡滑,所以就會(huì)走進(jìn)if條件里面,執(zhí)行((FrameCallback)action).doFrame方法卒暂,而action就是我們屬性動(dòng)畫(huà)調(diào)用mChoreographer是傳過(guò)來(lái)的mFrameCallback啊啊啊啊啊啄栓,這一連串操作。接下來(lái)肯定回到mFrameCallback的doFrame方法中了啊啊啊啊耙察簟j汲!诈嘿!
我們回去看下mFrameCallback的doFrame方法中堪旧,接著屬性動(dòng)畫(huà)分析:
#AnimationHandler
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
//1、重點(diǎn)
doAnimationFrame(getProvider().getFrameTime());
//2奖亚、同樣重點(diǎn)淳梦,這里就是動(dòng)畫(huà)連續(xù)的根源,只要mAnimationCallbacks.size() > 0昔字,就繼續(xù)將mFrameCallback進(jìn)行注冊(cè)爆袍,那么,下一幀脈沖信號(hào)到來(lái)就又會(huì)回調(diào)到該doFrame方法作郭,執(zhí)行1處操作陨囊。
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
在這里我們先來(lái)分析下2處,2處已經(jīng)標(biāo)注的很清晰了夹攒,這里就是動(dòng)畫(huà)連續(xù)的根源蜘醋,只要mAnimationCallbacks.size() > 0,就繼續(xù)將mFrameCallback進(jìn)行注冊(cè)咏尝,那么压语,下一幀脈沖信號(hào)到來(lái)就又會(huì)回調(diào)到該doFrame方法啸罢,執(zhí)行1處操作√ナ常看到這里我們大家大膽猜想下扰才,動(dòng)畫(huà)是怎么停止的呢?當(dāng)然是將該動(dòng)畫(huà)的callback從mAnimationCallbacks中移除啦斥季。到底是不是這樣子實(shí)現(xiàn)的呢训桶?我們后續(xù)會(huì)揭曉哈哈。我們跟進(jìn)去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酣倾、重點(diǎn)6娼摇!躁锡!
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
//2午绳、清除mAnimationCallbacks中的無(wú)用callback
cleanUpList();
}
我們先來(lái)看下2處,cleanUpList方法中做了清除mAnimationCallbacks中的無(wú)用callback操作映之。其實(shí)我們當(dāng)前屬性動(dòng)畫(huà)結(jié)束的時(shí)候會(huì)將mAnimationCallbacks中相關(guān)的callback直接置為null拦焚,cleanUpList方法中會(huì)對(duì)mAnimationCallbacks進(jìn)行遍歷操作,將callback為null的callback直接remove掉杠输,這樣子當(dāng)下次脈沖信號(hào)到來(lái)時(shí)只會(huì)處理其他正在執(zhí)行的動(dòng)畫(huà)赎败,當(dāng)前動(dòng)畫(huà)就結(jié)束了。
我們跟進(jìn)去1處看下蠢甲,不知道小伙伴還記不記得1處的callback是什么僵刮?1處的callback就是我們之前傳入的ObjectAnimator對(duì)象,so我們跟進(jìn)去ObjectAnimator的doAnimationFrame方法中看下,ObjectAnimator類(lèi)中沒(méi)有doAnimationFrame方法鹦牛,我們跟進(jìn)去它的父類(lèi)ValueAnimator中看下
#ValueAnimator
public final boolean doAnimationFrame(long frameTime) {
final long currentTime = Math.max(frameTime, mStartTime);
//1搞糕、重點(diǎn)!B贰窍仰!
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
//2、如果當(dāng)前動(dòng)畫(huà)執(zhí)行完畢礼殊,則調(diào)用endAnimation方法驹吮,后續(xù)就是我們上面剛提到的,
//將mAnimationCallbacks中相關(guān)的callback直接置為null
endAnimation();
}
return finished;
}
我們跟進(jìn)去1處的animateBasedOnTime方法中看下:
#ValueAnimator
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
float currentIterationFraction = getCurrentIterationFraction(
mOverallFraction, mReversing);
//重點(diǎn)!!!
animateValue(currentIterationFraction);
}
return done;
}
由于我們當(dāng)前是ObjectAnimator對(duì)象晶伦,而ObjectAnimator類(lèi)對(duì)ValueAnimator類(lèi)中的animateValue方法進(jìn)行了復(fù)寫(xiě)碟狞,所以會(huì)調(diào)用到ObjectAnimator類(lèi)的animateValue方法,我們跟進(jìn)去看下:
#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坝辫、重點(diǎn)篷就,調(diào)用super.animateValue方法
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//2射亏、重點(diǎn)
mValues[i].setAnimatedValue(target);
}
}
簡(jiǎn)單來(lái)講近忙,1處最終只是設(shè)置了當(dāng)前時(shí)間點(diǎn)對(duì)應(yīng)的動(dòng)畫(huà)數(shù)值竭业,2處調(diào)用setAnimatedValue方法最終才會(huì)導(dǎo)致View的重繪,也就是invalidate方法的調(diào)用及舍。我們先看下1處:
#ValueAnimator
@CallSuper
void animateValue(float fraction) {
//1未辆、如果我們?cè)O(shè)置了插值器,則會(huì)回調(diào)我們插值器的getInterpolation方法獲取進(jìn)度锯玛,
//如果我們沒(méi)有設(shè)置插值器咐柜,則使用默認(rèn)的插值器獲取動(dòng)畫(huà)進(jìn)度
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//2、重點(diǎn) 這里會(huì)回調(diào)的FloatPropertyValuesHolder對(duì)象的calculateValue方法攘残,將動(dòng)畫(huà)當(dāng)前的進(jìn)度傳入
mValues[i].calculateValue(fraction);
}
//3拙友、如果我們?cè)谕饷嬖O(shè)置了動(dòng)畫(huà)監(jiān)聽(tīng)器,則會(huì)回調(diào)動(dòng)畫(huà)監(jiān)聽(tīng)器的onAnimationUpdate方法歼郭,有沒(méi)有很熟悉哈哈
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
我們跟進(jìn)去FloatPropertyValuesHolder對(duì)象的calculateValue方法看下:
#FloatPropertyValuesHolder
@Override
void calculateValue(float fraction) {
mFloatAnimatedValue = mFloatKeyframes.getFloatValue(fraction);
}
這里mFloatKeyframes為FloatKeyframeSet對(duì)象遗契,我們之前設(shè)置動(dòng)畫(huà)起始值和結(jié)束值的時(shí)候?qū)λM(jìn)行了賦值,我們跟進(jìn)去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);
}
//重點(diǎn)k狗洹!泰涂!如果我們?cè)谕饷嬖O(shè)置了估值器鲫竞,即mEvaluator!=null逼蒙,則會(huì)回調(diào)我們?cè)O(shè)置估值器
//的evaluate方法獲取到當(dāng)前時(shí)間點(diǎn)對(duì)應(yīng)的動(dòng)畫(huà)數(shù)值从绘,否則按照以下計(jì)算當(dāng)前時(shí)間點(diǎn)對(duì)應(yīng)的動(dòng)畫(huà)數(shù)值!
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方法中主要是計(jì)算當(dāng)前時(shí)間點(diǎn)對(duì)應(yīng)的動(dòng)畫(huà)數(shù)值其做,然后將該動(dòng)畫(huà)數(shù)值return掉顶考,賦值給FloatPropertyValuesHolder對(duì)象的mFloatAnimatedValue字段。
好了,我們回過(guò)頭回到ObjectAnimator類(lèi)的animateValue方法中耸袜,1處的super完成后惨恭,我們看下2處的setAnimatedValue方法,2處的mValues[i]其實(shí)是我們之前設(shè)置的FloatPropertyValuesHolder對(duì)象,so我們就來(lái)到FloatPropertyValuesHolder對(duì)象的setAnimatedValue方法中:
@Override
void setAnimatedValue(Object target) {
//1渊季、重點(diǎn)!mFloatProperty就是我們外部調(diào)用傳入的TextView.TRANSLATION_X罚渐,
//所以這里會(huì)回調(diào)TextView.TRANSLATION_X的setValue方法却汉,
//將我們所要操作的控件(這里指mTvTest)和當(dāng)前時(shí)間點(diǎn)對(duì)應(yīng)的動(dòng)畫(huà)進(jìn)度作為參數(shù)傳入
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());
}
}
}
哈哈現(xiàn)在有點(diǎn)眉目了吧,1處mFloatProperty就是我們外部調(diào)用傳入的TextView.TRANSLATION_X荷并,所以這里會(huì)回調(diào)TextView.TRANSLATION_X的setValue方法合砂,將我們所要操作的控件(這里指mTvTest)和當(dāng)前時(shí)間點(diǎn)對(duì)應(yīng)的動(dòng)畫(huà)值作為參數(shù)傳入。那還不趕緊跟進(jìn)去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();
}
};
簡(jiǎn)單明了源织,TRANSLATION_X的setValue方法中直接調(diào)用 object.setTranslationX方法翩伪,也就是當(dāng)前動(dòng)畫(huà)所要操作的控件的setTranslationX方法微猖,將當(dāng)前時(shí)間點(diǎn)對(duì)應(yīng)的動(dòng)畫(huà)值作為參數(shù)傳入(這里是調(diào)用到mTvTest控件的setTranslationX方法)。在View的setTranslationX方法內(nèi)部會(huì)調(diào)用invalidate方法缘屹,從而完成View的重繪操作凛剥。
好了,到此為止轻姿,屬性動(dòng)畫(huà)源碼相關(guān)的解析就結(jié)束了犁珠,歡迎大家一起探討呀!