Android屬性動畫原始碼解析
屬性動畫是Android開發中常用的知識,網上大多數文章都是基於屬性動畫的用法來解說的,本文基於屬性動畫的原始碼,從原始碼角度去一探屬性動畫的究竟。
屬性動畫有兩個非常重要的類,分別是ObjectAnimator和ValueAnimator,其中前者繼承了後者,前者是對屬性動畫的api提供了更好的一層封裝,方便開發者使用。屬性動畫常見的用法如下:
ObjectAnimator animator = ObjectAnimator.ofFloat(targetView, "translationX", 100); animator.setInterpolator(new LinearInterpolator()); animator.setEvaluator(new FloatEvaluator()); animator.setDuration(100); animator.start();
上面涉及到兩個概念,插值器Interpolator和估值器Evaluator,插值器表示動畫播放過程中的某個時間點播放進度的百分比,是用來控制播放速率的,估值器用來計算某個播放進度點需要改變的view的屬性值,Evaluator.evaluate(float fraction, T startValue, T endValue) 是核心方法,fraction是進度百分比,startValue 和 endValue 表示動畫的起始值和結束值,通過這個三個值去計算對應的view的屬性值。
下面我們就基於上面的使用方式去追蹤分析一下原始碼,首先點進ofFloat方法如下:
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setFloatValues(values); return anim; } //new ObjectAnimator程式碼如下 private ObjectAnimator(Object target, String propertyName) { setTarget(target); setPropertyName(propertyName); } //setFloatValues方法的程式碼如下 @Override public void setFloatValues(float... values) { if (mValues == null || mValues.length == 0) { // No values yet - this animator is being constructed piecemeal. Init the values with // whatever the current propertyName is if (mProperty != null) { setValues(PropertyValuesHolder.ofFloat(mProperty, values)); } else { setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); } } else { super.setFloatValues(values); } }
可以看到首先建立一個ObjectAnimator物件,進行動畫view和動畫屬性名字的設定,然後通過setFloatValues設定我們一個動畫值。上面出現了一個PropertyValuesHolder.ofFloat方法,看起來像是將屬性相關值儲存在一個類中,我們進去看看:
public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) { return new FloatPropertyValuesHolder(property, values); } //下一步程式碼 public FloatPropertyValuesHolder(Property property, float... values) { super(property); setFloatValues(values); if (property instanceof FloatProperty) { mFloatProperty = (FloatProperty) mProperty; } } //setFloatValues的程式碼 public void setFloatValues(float... values) { super.setFloatValues(values); mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes; } //------ public void setFloatValues(float... values) { mValueType = float.class; mKeyframes = KeyframeSet.ofFloat(values); }
我們可以看到FloatPropertyValuesHolder是用來儲存相關屬性值的,其中出現了一個FloatKeyframes類,我們去看看這個類:
// 通過這個方法去儲存我們設定的屬性values
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
int numKeyframes = values.length;
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
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]);
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);
}
在KeyframeSet的ofFloat方法中,我們建立一個FloatKeyframes陣列,將屬性values儲存在陣列中。其中Keyframe我們翻譯叫關鍵幀,代表動畫執行過程中的一些重要的幀,比如開始、結束、中間值等等。這些值在動畫執行過程中都會用到。
到這裡分析完setValues(PropertyValuesHolder.ofFloat(mProperty, values))中的PropertyValuesHolder.ofFloat方法的作用,下面來看看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進行了賦值,這個值後面會經常用到,然後將屬性holder儲存到hashmap中,其中key是屬性名。到這裡我們分析完了ObjectAnimator.ofFloat(targetView, "translationX", 100);方法的整個過程,其實就是將我們設定的屬性值儲存起來。然後還有插值器和估值器,程式碼如下
//儲存插值器
@Override
public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
}
//儲存估值器
public void setEvaluator(TypeEvaluator value) {
if (value != null && mValues != null && mValues.length > 0) {
mValues[0].setEvaluator(value);
}
}
其中插值器是儲存在ValueAnimator中,而估值器是儲存在PropertyValuesHolder中。
上面屬性值都已經設定好了,開始進入start方法,這個方法裡面程式碼非常複雜,我們儘量簡要一點說明吧,做好準備進入start階段,先來看看start進入的關鍵程式碼:
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mReversing = playBackwards;
mSelfPulse = !mSuppressSelfPulseRequested;
// Special case: reversing from seek-to-0 should act as if not seeked at all.
if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
if (mRepeatCount == INFINITE) {
// Calculate the fraction of the current iteration.
float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
mSeekFraction = 1 - fraction;
} else {
mSeekFraction = 1 + mRepeatCount - mSeekFraction;
}
}
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);
}
}
}
我們從中挑出三個關鍵的方法逐一分析:
1.addAnimationCallback(0);
2.startAnimation();
3.setCurrentPlayTime(0);
下面我們來看看addAnimationCallback方法,
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
//AnimationHandler的addAnimationFrameCallback方法程式碼
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
//程式首先會執行這裡,因為此時mAnimationCallbacks中還沒有新增元素
getProvider().postFrameCallback(mFrameCallback);
}
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
這裡會呼叫AnimationHandler的新增監聽方法,其中又會轉到getProvider().postFrameCallback(mFrameCallback)的執行,我們先來看看那個mFrameCallback這個引數,再去追蹤getProvider方法
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
//重複呼叫
getProvider().postFrameCallback(this);
}
}
};
這個回撥介面中,我們發現一個有趣的地方,就是會重複呼叫getProvider().postFrameCallback,這種反覆操作的執行,有點像動畫的繪製了。那我們先轉去看看getProvider方法:
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
//其中MyFrameCallbackProvider類的程式碼
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
這裡出現了一個新類Choreographer,我們去看看:
//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();
final long dueTime = now + delayMillis;
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);
}
}
}
程式又走了幾步,經過判斷,我們的程式碼會走到scheduleFrameLocked(now),下面我們進去看看:
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()) {
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);
}
}
}
上面程式碼有點多,我們只看程式執行的部分,上面的會通過mHandler傳送一個MSG_DO_SCHEDULE_VSYNC訊息,所以我們又去看看handler是怎麼處理這個訊息的:
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
//這裡
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}
//下一步
void doScheduleCallback(int callbackType) {
synchronized (mLock) {
if (!mFrameScheduled) {
final long now = SystemClock.uptimeMillis();
if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now);
}
}
}
}
通過上面可以看到程式碼會執行到scheduleFrameLocked(now)方法,進去看看:
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
……
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
}
……
}
}
上面的程式碼會執行到scheduleVsyncLocked()方法,
private void scheduleVsyncLocked() {
mDisplayEventReceiver.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);
}
}
到這裡的時候,呼叫了一個jni方法,呵呵!其中引數mReceiverPtr是一個 jni 層指向 DisplayEventReceiver(子類 FrameDisplayEventReceiver) 的指標,jni 方法會回撥 FrameDisplayEventReceiver.onVsync() 方法,我們姑且不探究jni層是如何實現的,繼續看onVsync方法的程式碼:
@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);
}
這裡通過 mHandler 呼叫自身 FrameDisplayEventReceiver.run()方法,
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
//doFrame的程式碼
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
……
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);
}
……
}
我們可以看到開始執行各種doCallbacks方法了,這個是關鍵,下面快點進入去看看
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
//獲取我們之前儲存的callbacks
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) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
//執行callback
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);
}
}
其中我們會獲取到之前儲存的各種callback,然後通過run方法執行callback,其中c就是mCallbackQueues在下面的方法中儲存的元素
private void postCallbackDelayedInternal(int callbackType,
...................
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
//在這裡儲存的
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
...................
}
}
下面我們看看CallbackRecord 的run方法:
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
這裡的action就是我們上面執行過的mFrameCallback這個引數,再看看下面的程式碼清晰一點,因為繞了太多了,到這裡我們就知道了繪製動畫的核心,因為這個回撥會反覆執行,這就達到了繪製的效果。下面我要去看看下面的doAnimationFrame方法了
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
//重複呼叫
getProvider().postFrameCallback(this);
}
}
};
程式碼:
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)) {
//關鍵點
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
cleanUpList();
}
看關鍵callback.doAnimationFrame(frameTime),這個callback是ValueAnimator中的
getAnimationHandler().addAnimationFrameCallback(this, delay)
新增的,我們它所實現的介面方法:
public final boolean doAnimationFrame(long frameTime) {
...........
直接看這裡
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
endAnimation();
}
return finished;
}
我們繼續看 animateBasedOnTime(currentTime)
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
……
animateValue(currentIterationFraction);
}
return done;
}
//往下看
void animateValue(float fraction) {
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].calculateValue(fraction);
}
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
在這裡高興地看到了mValues的呼叫,好像是要賦fraction的值,就是播放進度,後面還呼叫了onAnimationUpdate方法,我們知道在ValueAnimator中有一個動畫更新的回撥,好像這裡找到了被呼叫的地方了
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
……
……
}
});
剛剛看的是ValueAnimator的方法,下面我們去ObjectAnimator中的animateValue方法
@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;
}
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].setAnimatedValue(target);
}
}
我們看到了mValues[i].setAnimatedValue(target)關鍵點,我們知道mValues中儲存的是FloatPropertyValuesHolder 物件,就是我們所儲存的各個屬性值,下面我們去看看具體的方法實現
void setAnimatedValue(Object target) {
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());
}
}
}
到這裡有幾個if判斷,我們不知道程式會走哪一步,那我們先放一下,回到最前面,我們還有兩個方法沒追蹤,下面我們來看看startAnimation()方法:
private void startAnimation() {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
System.identityHashCode(this));
}
mAnimationEndRequested = false;
initAnimation();
mRunning = true;
if (mSeekFraction >= 0) {
mOverallFraction = mSeekFraction;
} else {
mOverallFraction = 0f;
}
if (mListeners != null) {
notifyStartListeners();
}
}
這裡有一個初始化的initAnimation()方法,下面我們看看
void initAnimation() {
if (!mInitialized) {
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].init();
}
mInitialized = true;
}
}
//看看 FloatPropertyValuesHolder.init()方法
void init() {
if (mEvaluator == null) {
// We already handle int and float automatically, but not their Object
// equivalents
mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
(mValueType == Float.class) ? sFloatEvaluator :
null;
}
if (mEvaluator != null) {
// KeyframeSet knows how to evaluate the common types - only give it a custom
// evaluator if one has been set on this class
mKeyframes.setEvaluator(mEvaluator);
}
}
上面我們呼叫到FloatPropertyValuesHolder.init()方法,好像沒什麼值得發現的,下面我們來看看ObjectAnimator的initAnimation方法:
void initAnimation() {
if (!mInitialized) {
// mValueType may change due to setter/getter setup; do this before calling super.init(),
// which uses mValueType to set up the default type evaluator.
final Object target = getTarget();
if (target != null) {
final int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].setupSetterAndGetter(target);
}
}
super.initAnimation();
}
}
會呼叫 mValues[i].setupSetterAndGetter(target) 即FloatPropertyValuesHolder.setupSetterAndGetter(target),繼續跟進
void setupSetterAndGetter(Object target) {
setupSetter(target.getClass());
}
//繼續
void setupSetter(Class targetClass) {
if (mJniSetter != 0) {
return;
}
synchronized(sJNISetterPropertyMap) {
HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
boolean wasInMap = false;
if (propertyMap != null) {
wasInMap = propertyMap.containsKey(mPropertyName);
if (wasInMap) {
Long jniSetter = propertyMap.get(mPropertyName);
if (jniSetter != null) {
mJniSetter = jniSetter;
}
}
}
if (!wasInMap) {
String methodName = getMethodName("set", mPropertyName);
calculateValue(0f);
float[] values = (float[]) getAnimatedValue();
int numParams = values.length;
try {
mJniSetter = nGetMultipleFloatMethod(targetClass, methodName, numParams);
} catch (NoSuchMethodError e) {
// try without the 'set' prefix
try {
mJniSetter = nGetMultipleFloatMethod(targetClass, mPropertyName,
numParams);
} catch (NoSuchMethodError e2) {
// just try reflection next
}
}
if (propertyMap == null) {
propertyMap = new HashMap<String, Long>();
sJNISetterPropertyMap.put(targetClass, propertyMap);
}
propertyMap.put(mPropertyName, mJniSetter);
}
}
}
}
這裡會對mJniSetter 進行賦值,所以回到上面幾個if的判斷中,我們可以知道,程式會走
if (mJniSetter != 0) {
nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
return;
}
這裡會通過jni指標,修改對應的屬性引數,即view.setTranslanteX(value)方法。程式碼到這裡,我們完成了view屬性的設定,整個動畫過程中,隨著動畫的進度不斷改變,屬性值也會不斷改變,然後通過我們的設定,目標view的屬性值也會不斷改變,從而達到屬性動畫的效果。
下面我們看看最後第一個關鍵方法setCurrentPlayTime(0)
public void setCurrentPlayTime(long playTime) {
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
// setCurrentPlayTime(0) 還是會呼叫 setCurrentFraction(mSeekFraction)
public void setCurrentFraction(float fraction) {
initAnimation();
fraction = clampFraction(fraction);
mStartTimeCommitted = true; // do not allow start time to be compensated for jank
if (isPulsingInternal()) {
long seekTime = (long) (getScaledDuration() * fraction);
long currentTime = AnimationUtils.currentAnimationTimeMillis();
// Only modify the start time when the animation is running. Seek fraction will ensure
// non-running animations skip to the correct start time.
mStartTime = currentTime - seekTime;
} else {
// If the animation loop hasn't started, or during start delay, the startTime will be
// adjusted once the delay has passed based on seek fraction.
mSeekFraction = fraction;
}
mOverallFraction = fraction;
final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
animateValue(currentIterationFraction);
}
可以看到上面會呼叫到animateValue(currentIterationFraction)方法,我們知道這個方法就是對view屬性的更新,所以可以知道在呼叫了startAnimation()之後,就會立即進行一次view的更新操作,此時引數fraction為0。
上面就是屬性動畫原始碼解析全過程了,實在是太長了,閱讀原始碼我們還是要抓住關鍵的步驟,不能沉溺於不重要的細節,在開發路上我們共勉吧!