ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0.3f, 1.0f);
alphaAnim.setInterpolator(new LinearInterpolator());
alphaAnim.setDuration(1000);
alphaAnim.start();
属性动画主要使用 ObjectAnimator 和 ValueAnimator 两个类,其中ObjectAnimator 是 ValueAnimator 的子类,ObjectAnimator 对 ValueAnimator 做了一层封装,实现了对属性值的自动改变,api调用更加简略
我们一般使用 ObjectAnimator 的静态方法去创建 ObjectAnimator 对象。例如上面的ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0.3f, 1.0f)
,我们来看下它里面是如何创建的
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
private ObjectAnimator(Object target, String propertyName) {
//设置目标对象
setTarget(target);
//设置属性名
setPropertyName(propertyName);
}
首先设置目标对象
public void setTarget(@Nullable Object target) {
final Object oldTarget = getTarget();
if (oldTarget != target) {
//如果目标对象改变,比如从默认的null变为非null
if (isStarted()) {
//如果之前动画已经开始了,先取消掉
cancel();
}
mTarget = target == null ? null : new WeakReference<Object>(target);
// 新目标应在starting之前引起重新初始化
mInitialized = false;
}
}
然后设置属性名
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.
//此时此处为null,必定不会走下面的方法块
if (mValues != null) {
...
}
mPropertyName = propertyName;
//新的property应该在启动之前引起重新初始化
mInitialized = false;
}
@Override
public void setFloatValues(float... values) {
if (mValues == null || mValues.length == 0) {
//mValue没有赋值过,所以进入if方法块
if (mProperty != null) {
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {
//由于只设置了mPropertyName,所以走此处else的方法块
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
}
} else {
super.setFloatValues(values);
}
}
由于此时mValues没有赋值过,所以会先执行PropertyValuesHolder.ofFloat(mPropertyName, values)
方法进行创建PropertyValuesHolder
public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
return new FloatPropertyValuesHolder(propertyName, values);
}
调用了 FloatPropertyValuesHolder 的构造方法创建 PropertyValuesHolder 对象,
public FloatPropertyValuesHolder(String propertyName, float... values) {
super(propertyName);
setFloatValues(values);
}
先是使用了父类 PropertyValuesHolder 的构造方法初始化 propertyName
private PropertyValuesHolder(String propertyName) {
mPropertyName = propertyName;
}
然后是 FloatPropertyValuesHolder 的 setFloatValues 方法
public void setFloatValues(float... values) {
super.setFloatValues(values);
//FloatPropertyValuesHolder 自己的对象赋值。
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}
先是调用了父类 PropertyValuesHolder 的 setFloatValues 方法
public void setFloatValues(float... values) {
//mValueType提供值的类型。此信息既可用于推导settergetter函数,也可用于推导TypeEvaluator的类型。
mValueType = float.class;
//定义此动画的一组关键帧(时间值对)。
mKeyframes = KeyframeSet.ofFloat(values);
}
先是赋值了mValueType,用于定义值得类型。有调用了 KeyframeSet.ofFloat 方法,生成动画的关键帧,我们再看下 KeyframeSet.ofFloat 方法
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
//记录values的个数,
int numKeyframes = values.length;
//创建关键帧数组,至少有两个值
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
if (numKeyframes == 1) {
//如果用户只给了一个值,第0个关键帧键值对为<0,0>,意思是fraction为0时值为0
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
//第1个关键帧赋值为<1,values[0]>,意思是fraction为1时,值为values[0]
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
if (Float.isNaN(values[0])) {
badValue = true;
}
} else {
//超过一个关键帧,先设置第0个关键帧为<0,values[0]>
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
//然后依次设置第i个关键帧为<(i/(numKeyframes - 1)),values[i])>
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);
}
这里使用穿的values数组,生成关键帧数组,然后使用这些关键帧数据生成 FloatKeyframeSet 对象。
关键帧数组的生成规则是
如果只有一个值,则有两个关键帧,第0个关键帧键值对为<0,0>,意思是fraction为0时值为0
超过一个关键帧,先设置第0个关键帧为<0,values[0]>,然后依次设置第i个关键帧为<(i/(numKeyframes - 1)),values[i])>
到这里我们往后翻,回到 setFloatValues(float… values) 方法,为了防止忘了,我们再看一遍
@Override
public void setFloatValues(float... values) {
...
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
...
}
上面我们已经看了 PropertyValuesHolder.ofFloat 如何创建 FloatPropertyValuesHolder 对象,我们再继续看
setValues方法。
public void setValues(PropertyValuesHolder... values) {
int numValues = values.length;
//对mValues进行赋值
mValues = values;
//创建numValues个对象的map
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
PropertyValuesHolder valuesHolder = values[i];
//根据PropertyName,将valuesHolder存储起了,便于查找
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
setValues方法是 ObjectAnimator 父类 ValueAnimator 类 的方法,此处根据PropertyName,将valuesHolder存储起了,便于后面查找
看到这里好像只是一堆四处调用进行赋值对象初始化,没啥亮点,唯一复杂点的就是关键帧的生成。既然这样我们就看下动画的开发方法,start()方法
@Override
public void start() {
...
super.start();
}
此处除了一些我们不需要关注的代码外就是对父类 ValueAnimator#start 方法的调用了,我们进去看一下
public void start() {
start(false);
}
调用了一个同名方法 start(boolean playBackwards) ,其中参数标志是否是向后播放,也就是是否是反着做动画,这里传的是false,在调用动画的reverse方法时,此处会传true,我们看下里面是怎样的
private void start(boolean playBackwards) {
//检查是有Looper,没有的话抛出异常
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mReversing = playBackwards;
mSelfPulse = !mSuppressSelfPulseRequested;
if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
...
}
mStarted = true;
mPaused = false;
mRunning = false;
mAnimationEndRequested = false;
// 在调用start()时重置mLastFrameTime,以便如果动画正在运行,则调用start())会将动画置于开始了但尚未到达的第一帧阶段。
mLastFrameTime = -1;
mFirstFrameTime = -1;
mStartTime = -1;
//关键点1
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// 如果没有开始延迟,请初始化动画并立即通知开始侦听器,以与先前的行为保持一致。否则,将其推迟到开始延迟后的第一帧。
//关键点2
startAnimation();
if (mSeekFraction == -1) {
// 无seek,从播放时间0开始。请注意,我们不使用分数0的原因是,对于持续时间为0的动画,我们希望与N前行为保持一致:立即跳至最终值。
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
这里有两个关键点,我们先来看第一个addAnimationCallback(0)方法
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
这里通过调用getAnimationHandler()方法获取对象,然后又调用了addAnimationFrameCallback方法,我们先看下getAnimationHandler()方法获取到了啥。
public AnimationHandler getAnimationHandler() {
return AnimationHandler.getInstance();
}
继续看AnimationHandler.getInstance()
public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
此处使用了 ThreadLocal 线程本地变量,使得对象线程单例,很明显是使用了new AnimationHandler()
语句初始化了对象,我们进入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));
}
}
我们又要看下 getProvider() 方法获取了什么对象
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
很明显是MyFrameCallbackProvider类的实例,我们再进去看下他的postFrameCallback方法
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
又交给了mChoreographer,再看下Choreographer的postFrameCallback方法
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");
}
//注意这个类型CALLBACK_ANIMATION和FRAME_CALLBACK_TOKEN
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;
//这里的action就是之前我们传入的action,这里将其添加到了queues里
//注意这里按照callbackType进行了分组,当前的类型是CALLBACK_ANIMATION
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
//我们的delay一直为0,走这里
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
先看一下mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token)语句
public void addCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
CallbackRecord entry = mHead;
if (entry == null) {
mHead = callback;
return;
}
if (dueTime < entry.dueTime) {
callback.next = entry;
mHead = callback;
return;
}
while (entry.next != null) {
if (dueTime < entry.next.dueTime) {
callback.next = entry.next;
break;
}
entry = entry.next;
}
entry.next = callback;
}
这里通过obtainCallbackLocked方法获取了一个对象,然后将对象按照dueTime顺序插入到了一个链表里
再看下obtainCallbackLocked方法
private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
CallbackRecord callback = mCallbackPool;
if (callback == null) {
callback = new CallbackRecord();
} else {
mCallbackPool = callback.next;
callback.next = null;
}
callback.dueTime = dueTime;
callback.action = action;
//注意此处token为FRAME_CALLBACK_TOKEN,后面会用到
callback.token = token;
return callback;
}
很明显此处获取了一个CallbackRecord 对象,然后把之前传过来的信息记录了下来,注意这个action是之前我们穿过来的callback。
我们再回到postCallbackDelayedInternal方法
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
...
if (dueTime <= now) {
//我们的delay一直为0,走这里
scheduleFrameLocked(now);
} else {
...
}
}
}
由于我们的delay一直为0,走scheduleFrameLocked方法
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
//一开始肯定可以走进if语句块
mFrameScheduled = true;
if (USE_VSYNC) {
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);
}
}
}
一开始肯定可以走进if语句块,而下面代码则要么直接调用 scheduleVsyncLocked() 方法,要么通过handler走 scheduleVsyncLocked() 方法,所以我们还是要看 scheduleVsyncLocked() 方法
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
这里调用了一个鬼mDisplayEventReceiver的scheduleVsync方法,而mDisplayEventReceiver是类 FrameDisplayEventReceiver 的实例,而scheduleVsync方法是类 FrameDisplayEventReceiver 的父类 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);
}
}
指向了native方法,我们只能看下mReceiverPtr是啥了。
private long mReceiverPtr;
public DisplayEventReceiver(Looper looper, int vsyncSource) {
...
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,vsyncSource);
...
}
调用了native的init方法,传入了一个DisplayEventReceiver的软引用,传入了自己,那么理论上这个类应该有来自native的回调,通过看注释我们知道有下面两个方法被navive对象调用
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}
// Called from native code.
@SuppressWarnings("unused")
private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
onHotplug(timestampNanos, builtInDisplayId, connected);
}
而根据之前我们调用的方法名判断,应该是回掉dispatchVsync方法,这个方法里调用了onVsync方法,而刚好FrameDisplayEventReceiver类重写了这个方法,我们回到FrameDisplayEventReceiver类看下它的onVsync方法
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);
}
这里通过Handler将自己作为一个Runnable对象加入到了队列中。我们再看下他的run方法
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
调用了Choreographer的doFrame方法
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);
}
...
}
我们注意到这里有个 CALLBACK_ANIMATION 类型,而之前我们在Choreographer的 postFrameCallbackDelayed 方法传入过
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
postCallbackDelayedInternal(CALLBACK_ANIMATION,
callback, FRAME_CALLBACK_TOKEN, delayMillis);
}
所以我么看下doCallbacks方法
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
if (callbackType == Choreographer.CALLBACK_COMMIT) {
...
}
}
try {
for (CallbackRecord c = callbacks; c != null; c = c.next) {
...
//重点在这里
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
}
}
这里主要是调用了CallbackRecord的run方法,我们进去看一下
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
//走这里,我们之前赋值token为FRAME_CALLBACK_TOKEN
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
由于我们之前传入的token为FRAME_CALLBACK_TOKEN所以会走(FrameCallback)action的doFrame方法,大家应该还记得我们的action就是我们AnimationHandler的之前传入的mFrameCallback对象吧,我们再会看一下,这个调用在AnimationHandler#addAnimationFrameCallback 方法里
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
...
}
我们去研究下mFrameCallback对象的doFrame方法
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
先是调用doAnimationFrame方法更新动画,然后再次调用postFrameCallback方法,这样就形成了动画的连续,每一帧都会调用一次doAnimationFrame方法更新动画,我们看下doAnimationFrame方法
private void doAnimationFrame(long frameTime) {
long currentTime = SystemClock.uptimeMillis();
final int size = mAnimationCallbacks.size();
for (int i = 0; i < size; i++) {
//之前在addAnimationFrameCallback方法里添加的
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
if (isCallbackDue(callback, currentTime)) {
//这里调用doAnimationFrame方法
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
//清空callback
cleanUpList();
}
我们之前在addAnimationFrameCallback方法里添加的AnimationFrameCallback对象(其实就是ObjectAnimator的实例),在这里调用了它的doAnimationFrame方法,由于这个AnimationFrameCallback对象是ObjectAnimator的实例,而AnimationFrameCallback的父类ValueAnimator实现了doAnimationFrame方法
public final boolean doAnimationFrame(long frameTime) {
if (mStartTime < 0) {
// 第一帧。如果存在启动延迟,则在此帧之后将开始启动延迟倒计时。
mStartTime = mReversing ? frameTime : frameTime + (long) (mStartDelay * sDurationScale);
}
// 处理 pause/resume
if (mPaused) {
//如果暂停状态,移除callback
mPauseTime = frameTime;
removeAnimationCallback();
return false;
} else if (mResumed) {
mResumed = false;
if (mPauseTime > 0) {
//动画暂停持续时间的偏移量
mStartTime += (frameTime - mPauseTime);
}
}
if (!mRunning) {
...
}
mLastFrameTime = frameTime;
final long currentTime = Math.max(frameTime, mStartTime);
//关键点在animateBasedOnTime这里
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
//如果结束了,关闭动画
endAnimation();
}
return finished;
}
我们看下需要注意的animateBasedOnTime方法
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
final long scaledDuration = getScaledDuration();
final float fraction = scaledDuration > 0 ?
(float)(currentTime - mStartTime) / scaledDuration : 1f;
final float lastFraction = mOverallFraction;
final boolean newIteration = (int) fraction > (int) lastFraction;
final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
(mRepeatCount != INFINITE);
if (scaledDuration == 0) {
// 0 duration animator, ignore the repeat count and skip to the end
done = true;
} else if (newIteration && !lastIterationFinished) {
// Time to repeat
if (mListeners != null) {
int numListeners = mListeners.size();
for (int i = 0; i < numListeners; ++i) {
mListeners.get(i).onAnimationRepeat(this);
}
}
} else if (lastIterationFinished) {
done = true;
}
//计算Fraction
mOverallFraction = clampFraction(fraction);
float currentIterationFraction = getCurrentIterationFraction(
mOverallFraction, mReversing);
//这里更新每一帧的动画值
animateValue(currentIterationFraction);
}
return done;
}
animateValue 方法更新每一帧的动画值,这里要注意ObjectAnimator覆写了这个方法,所以我们要看ObjectAnimator类的animateValue方法
@Override
void animateValue(float fraction) {
final Object target = getTarget();
if (mTarget != null && target == null) {
...
}
//此处会调用AnimatorUpdateListener的onAnimationUpdate方法
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//注意这里
mValues[i].setAnimatedValue(target);
}
}
这里调用了mValues数组每个对象的setAnimatedValue方法,而mValues数组的对象为FloatPropertyValuesHolder的实例,我们看下FloatPropertyValuesHolder的setAnimatedValue方法
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;
}
}
}
这里有多个分支,我们无法判断他是走了哪里,但看走后一个分支可以知道他是通过反射调用了方法修改值。
我们再回到 ValueAnimator#start 方法,
private void start(boolean playBackwards) {
...
// 在调用start()时重置mLastFrameTime,以便如果动画正在运行,则调用start())会将动画置于开始了但尚未到达的第一帧阶段。
mLastFrameTime = -1;
mFirstFrameTime = -1;
mStartTime = -1;
//关键点1
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// 如果没有开始延迟,请初始化动画并立即通知开始侦听器,以与先前的行为保持一致。否则,将其推迟到开始延迟后的第一帧。
//关键点2
startAnimation();
if (mSeekFraction == -1) {
// 关键点3
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
它里面有3个关键的地方,接下来我们来看关键点2 ValueAnimator#startAnimation 方法
private void startAnimation() {
...
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;
}
}
好像只有mValues[i].init() 方法有点价值,我们知道 mValues 是 FloatPropertyValuesHolder 类型的数组,而init方法是它的父类 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);
}
}
好像看下来也没啥东西,我们再回头看下,其实我们一直看的都是 ValueAnimator的方法,但我们实际使用的是它的子类 ObjectAnimator ,而 ObjectAnimator 覆写了 initAnimation 方法
我们再去看一下
void initAnimation() {
if (!mInitialized) {
final Object target = getTarget();
if (target != null) {
final int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//初始化setter和getter
mValues[i].setupSetterAndGetter(target);
}
}
super.initAnimation();
}
}
在这里我们似乎看到了setAnimatedValue 方法里的 的各个 setter 的赋值了,我们进去看下
void setupSetterAndGetter(Object target) {
if (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) {
//初始化setter
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) {
//初始化getter
setupGetter(targetClass);
if (mGetter == null) {
// Already logged the error - just return to avoid NPE
return;
}
}
...
}
}
}
}
我们再看 setupSetter 方法
void setupSetter(Class targetClass) {
//mConverter应该为null,在ofFloat时不会赋值,这里应该是mValueType=Float.class
Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}
就在看setupSetterOrGetter 方法吧
private Method setupSetterOrGetter(Class targetClass,
HashMap<Class, HashMap<String, Method>> propertyMapMap,
String prefix, Class valueType) {
Method setterOrGetter = null;
synchronized(propertyMapMap) {
//获取targetClass对应的map
HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
boolean wasInMap = false;
if (propertyMap != null) {
wasInMap = propertyMap.containsKey(mPropertyName);
if (wasInMap) {
setterOrGetter = propertyMap.get(mPropertyName);
}
}
if (!wasInMap) {
//第一次肯定找不到,进入方法块
//获取mPropertyName对应的setter或getter方法
setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
if (propertyMap == null) {
//创建targetClass对应的map,并缓存
propertyMap = new HashMap<String, Method>();
propertyMapMap.put(targetClass, propertyMap);
}
//混存setter或getter方法
propertyMap.put(mPropertyName, setterOrGetter);
}
}
return setterOrGetter;
}
看来 getPropertyFunction才是真正 获取mPropertyName对应的setter或getter方法的方法
private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
// TODO: faster implementation...
Method returnVal = null;
//根据prefix组装getter或setter方法名
String methodName = getMethodName(prefix, mPropertyName);
Class args[] = null;
//此时的valueType应该为float.class
if (valueType == null) {
...
} else {
args = new Class[1];
Class typeVariants[];
if (valueType.equals(Float.class)) {
...
} else {
typeVariants = new Class[1];
typeVariants[0] = valueType;
}
for (Class typeVariant : typeVariants) {
args[0] = typeVariant;
try {
//反射获取getter或setter方法
returnVal = targetClass.getMethod(methodName, args);
if (mConverter == null) {
// change the value type to suit
mValueType = typeVariant;
}
return returnVal;
} catch (NoSuchMethodException e) {
// Swallow the error and keep trying other variants
}
}
// If we got here, then no appropriate function was found
}
if (returnVal == null) {
...
}
return returnVal;
}
通过上面一系列调用我们可以看到,我们初始化了mSetter,是属性名的setter方法Method的引用,这里就跟setAnimatedValue 对应起来了,setAnimatedValue 方法可以用反射修改target的值
最后我们来看setCurrentPlayTime(0)方法
public void setCurrentPlayTime(long playTime) {
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
走后其实还是走到了 setCurrentFraction 方法
public void setCurrentFraction(float fraction) {
initAnimation();
//修正fraction在0-mRepeatCount + 1之间,如果不是无线循环的话
fraction = clampFraction(fraction);
mStartTimeCommitted = true;
...
final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
//更新属性值
animateValue(currentIterationFraction);
}
setCurrentFraction 最后调用了animateValue方法,这里应该是设置属性值为初始值
最后贴一张别人画的流程图
// Swallow the error and keep trying other variants
}
}
// If we got here, then no appropriate function was found
}
if (returnVal == null) {
...
}
return returnVal;
}
通过上面一系列调用我们可以看到,我们初始化了mSetter,是属性名的setter方法Method的引用,这里就跟setAnimatedValue 对应起来了,setAnimatedValue 方法可以用反射修改target的值
### setCurrentFraction()方法
最后我们来看setCurrentPlayTime(0)方法
~~~java
public void setCurrentPlayTime(long playTime) {
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
走后其实还是走到了 setCurrentFraction 方法
public void setCurrentFraction(float fraction) {
initAnimation();
//修正fraction在0-mRepeatCount + 1之间,如果不是无线循环的话
fraction = clampFraction(fraction);
mStartTimeCommitted = true;
...
final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
//更新属性值
animateValue(currentIterationFraction);
}
setCurrentFraction 最后调用了animateValue方法,这里应该是设置属性值为初始值
最后贴一张别人画的流程图