源码阅读_属性动画执行过程
在Android开发中有很多地方使用到了属性动画,阅读源码是熟悉API以及相关代码最直接的方式。
在平时开发中使用属性动画最多的就是这类的代码
val animator = ObjectAnimator.ofFloat(mView, "alpha", 0f, 100f, 50f)
animator.duration = 1000
animator.startDelay = 300
animator.start()
封装数据
代码中第一句ObjectAnimator.ofFloat(…)
,直接打开源码(ObjectAnimator.java)
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
在ofFloat方法中第一行代码是创建一个ObjectAnimator
对象,构造函数中传入执行动画的View,以及属性名。
private ObjectAnimator(Object target, String propertyName) {
setTarget(target);
setPropertyName(propertyName);
}
打开构造函数的代码,可以看到函数中又调用两个方法,看意思感觉挺明显一个是设置View,一个是设置属性名。
还是看一下setTarget
方法和setPropertyName
方法具体执行了什么逻辑
在setTarget
方法中,
- 先获取mTarget,判断获取的mTarget和目标View是否是同一个控件,很明显之前没有设置过mTarget,所以
if (oldTarget != target)
为true; - 判断动画状态,如果是开始执行动画了就取消;
- 将目标View保存到全局变量mTarget中。
private WeakReference<Object> mTarget;
public Object getTarget() {
return mTarget == null ? null : mTarget.get();
}
@Override
public void setTarget(@Nullable Object target) {
final Object oldTarget = getTarget();
if (oldTarget != target) {
if (isStarted()) {
cancel();
}
mTarget = target == null ? null : new WeakReference<Object>(target);
// New target should cause re-initialization prior to starting
mInitialized = false;
}
}
在setPropertyName
方法中
- 判断
mValues
是否为空;(第一次一定为空, 如果不为空,则用当前值替换数组中的第一个值,以及替换mValuesMap
) - 保存属性名至全局变量
mPropertyName
; - 设置初始化标识false
//用于保存属性名的数组
PropertyValuesHolder[] mValues;
//用于保存属性名的HashMap
HashMap<String, PropertyValuesHolder> mValuesMap;
public void setPropertyName(@NonNull String propertyName) {
// mValues could be null if this is being constructed piecemeal. Just record the
// propertyName to be used later when setValues() is called if so.
if (mValues != null) {
PropertyValuesHolder valuesHolder = mValues[0];
String oldName = valuesHolder.getPropertyName();
valuesHolder.setPropertyName(propertyName);
mValuesMap.remove(oldName);
mValuesMap.put(propertyName, valuesHolder);
}
mPropertyName = propertyName;
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
这样构造函数执行的内容都搞清楚了,继续看下面设置的代码
animator.duration = 1000
animator.startDelay = 300
这部分源码就很简单了,就是保存属性
// ObjectAnimator类中
@Override
@NonNull
public ObjectAnimator setDuration(long duration) {
super.setDuration(duration);
return this;
}
//父类ValueAnimator中
@Override
public ValueAnimator setDuration(long duration) {
if (duration < 0) {
throw new IllegalArgumentException("Animators cannot have negative duration: " +
duration);
}
mDuration = duration;
return this;
}
注册垂直同步信号
继续下一行代码animator.start()
;
这个方法里面主要操作一个是取消监听,一个是执行父类的start()
方法。
@Override
public void start() {
//AnimationHandler 并不是Android中的Handler,这里可以理解为一个单例工具类
//取消掉animator之前设置的回调
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();
}
在start()
方法中首先后去获取了一个AnimationHandler
对象的单例,再调用这个单例的autoCancelBasedOn()
方法。
其实AnimationHandler
对象并不是Android中的Handler,这里可以理解为一个工具类。
其中的autoCancelBasedOn()
方法中执行的内容大致为遍历取消动画下一帧回调监听。(至于哪里注册、使用到这个监听,下面会讲到)
public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
void autoCancelBasedOn(ObjectAnimator objectAnimator) {
for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
AnimationFrameCallback cb = mAnimationCallbacks.get(i);
if (cb == null) {
continue;
}
if (objectAnimator.shouldAutoCancel(cb)) {
((Animator) mAnimationCallbacks.get(i)).cancel();
}
}
}
取消完监听之后调用了父类的start()
方法,父类的start()
方法中又调用了重载的start(false)
方法。
这个重载的start(false)
方法就比较重要了,一开始它检查了是否在UI线程执行,又设置动画是否反向播放(从来没有用过反向播放),反向播放的操作逻辑,以及一些状态设置等等。
接下来执行了它比较重要的三个方法addAnimationCallback(0)
、startAnimation();
和setCurrentPlayTime(0)
@Override
public void start() {
//重载start的方法 参数是是否反向播放
start(false);
}
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
// 动画是否反向播放
mReversing = playBackwards;
// mSuppressSelfPulseRequested,这个值通过方法startWithoutPulsing设置,就把他默认当作false即可
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);
}
}
}
addAnimationCallback(0)
方法中,主要执行的逻辑就是前面提到过的AnimationHandler
中注册AnimationFrameCallback
监听。
因为前面移除了所有监听所以代码会执行getProvider().postFrameCallback(mFrameCallback)
。
// ValueAnimator 类中
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
/**
* AnimationHandler 的 addAnimationFrameCallback方法代码
* Register to get a callback on the next frame after the delay.
*/
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));
}
}
先看getProvider().postFrameCallback(mFrameCallback)
这行代码的参数mFrameCallback
,再去了解getProvider
方法。
这是一个回调接口,回调方法doFrame
中只要mAnimationCallbacks
大于0就会调用getProvider().postFrameCallback(this)
,这就有点动画反复绘制的意思了。(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);
}
}
};
继续看getProvider
方法。方法中创建了一个对象MyFrameCallbackProvider
。
这个类又出现了一个比较重要的参数Choreographer
。
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
//AnimationHandler 内部类
private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
}
可以看到前面回调函数中的重复调用的postFrameCallback
方法中调用了Choreographer
类中的postFrameCallback
方法。
postFrameCallback
方法中又调用了postFrameCallbackDelayed
方法。
postFrameCallbackDelayed
方法中又调用了postCallbackDelayedInternal
方法。
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) {
......
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)
中,首先看到一个布尔值USE_VSYNC
,这个值是用来表示是否开启垂直同步。
// Enable/disable vsync for animations and drawing.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
private static final boolean USE_VSYNC = SystemProperties.getBoolean(
"debug.choreographer.vsync", true);
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);
}
}
}
如果开启了垂直同步,则判断当前是否在Looper线程上运行,如果在Looper线程上运行,那么立即调度vsync,否则,从UI线程发布一条消息来调度vsync
FrameDisplayEventReceiver
类中的scheduleVsync
方法就是向native层注册监听垂直同步信号,其中参数mReceiverPtr
就是一个jni层指向DisplayEventReceiver
(的子类FrameDisplayEventReceiver
)的指针,jni方法会回调FrameDisplayEventReceiver
的onVsync
方法。
从UI线程发布一条消息来调度vsync最后也是执行了scheduleVsyncLocked
方法。
private void scheduleFrameLocked(long now) {
.......
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
......
}
private final class FrameHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
.......
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
.......
}
}
}
void doScheduleVsync() {
synchronized (mLock) {
if (mFrameScheduled) {
scheduleVsyncLocked();
}
}
}
private boolean isRunningOnLooperThreadLocked() {
return Looper.myLooper() == mLooper;
}
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
// FrameDisplayEventReceiver类中
@UnsupportedAppUsage
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);
}
}
收到垂直同步信号回调之后,onVsync
方法被回调,这个方法的最后执行了发送Handle
(Message.obtain(mHandler, this)
),执行了自己的run
方法。
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, 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);
}
}
run
方法中调用了doFrame
,doFrame
方法里面各种执行doCallbacks
方法。
在doCallbacks
方法中先获取之前保存的callback,然后通过run方法执行callback,
@UnsupportedAppUsage
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);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
......
}
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
animation to start.
final long now = System.nanoTime();
//先获取之前保存的callback
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) {
//执行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
方法是从postCallbackDelayedInternal
方法中加入队列的,所以上面的c就是回调方法。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
......
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
......
}
而这里的callback
方法,就是Choreographer.FrameCallback
,这就有回到了这里。
这个回调中先执行doAnimationFrame
方法,再接续注册回调方法。
而在doAnimationFrame
方法中比较重要的是这句callback.doAnimationFrame(frameTime)
,这里的callback
就是ValueAnimator
,这就回到了ValueAnimator
中的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();
}
//ValueAnimator 中
getAnimationHandler().addAnimationFrameCallback(this, delay)
ValueAnimator
中的doAnimationFrame
方法。
一直深入进入,终于看到之前保存的mValues
的使用,它被赋上了进度值,,这个方法中还回调了监听。
* @hide
*/
public final boolean doAnimationFrame(long frameTime) {
......
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
endAnimation();
}
return finished;
}
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);
}
}
}
但是貌似还是少了和目标View关联。
ObjectAnimator
类中的animateValue
方法,有这样一句mValues[i].setAnimatedValue(target)
关键语句
我们知道mValues
中保存的是FloatPropertyValuesHolder
对象,就是我们所保存的各个属性值
@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);
}
}
FloatPropertyValuesHolder
类中setAnimatedValue
中,mSetter不为空的时候利用反射执行了set方法。
void setAnimatedValue(Object target) {
if (mProperty != null) {
mProperty.set(target, getAnimatedValue());
}
if (mSetter != null) {
try {
mTmpValueArray[0] = getAnimatedValue();
mSetter.invoke(target, mTmpValueArray);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
Log.e("PropertyValuesHolder", e.toString());
}
}
}
初始化Setter方法
前面说到了三个重要的方法,现在说第二个startAnimation()
。
startAnimation()
方法中执行了initAnimation()
,initAnimation()
方法中调用了PropertyValuesHolder
类的init()
方法。
也没有什么特别的地方
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();
}
}
@CallSuper
void initAnimation() {
if (!mInitialized) {
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].init();
}
mInitialized = true;
}
}
// PropertyValuesHolder
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);
}
}
再看ObjectAnimator
的initAnimation
方法,会调用 FloatPropertyValuesHolder.setupSetterAndGetter(target)
。
这个方法中对之前没有找到的mSetter进行了赋值。
@Override
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();
}
}
// FloatPropertyValuesHolder 类中
void setupSetterAndGetter(Object target) {
if (mProperty != null) {
// check to make sure that mProperty is on the class of target
try {
Object testValue = null;
List<Keyframe> keyframes = mKeyframes.getKeyframes();
int keyframeCount = keyframes == null ? 0 : keyframes.size();
for (int i = 0; i < keyframeCount; i++) {
Keyframe kf = keyframes.get(i);
if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (testValue == null) {
testValue = convertBack(mProperty.get(target));
}
kf.setValue(testValue);
kf.setValueWasSetOnStart(true);
}
}
return;
} catch (ClassCastException e) {
Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +
") on target object " + target + ". Trying reflection instead");
mProperty = null;
}
}
// We can't just say 'else' here because the catch statement sets mProperty to null.
if (mProperty == null) {
Class targetClass = target.getClass();
if (mSetter == null) {
setupSetter(targetClass);
}
List<Keyframe> keyframes = mKeyframes.getKeyframes();
int keyframeCount = keyframes == null ? 0 : keyframes.size();
for (int i = 0; i < keyframeCount; i++) {
Keyframe kf = keyframes.get(i);
if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (mGetter == null) {
setupGetter(targetClass);
if (mGetter == null) {
// Already logged the error - just return to avoid NPE
return;
}
}
try {
Object value = convertBack(mGetter.invoke(target));
kf.setValue(value);
kf.setValueWasSetOnStart(true);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
Log.e("PropertyValuesHolder", e.toString());
}
}
}
}
}
void setupSetter(Class targetClass) {
Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}
有了mSetter这个参数动画效果就能执行起来了。
往set方法总设置值
最后看看最后第一个关键方法setCurrentPlayTime(0)
public void setCurrentPlayTime(long playTime) {
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
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。