属性动画是Android开发中常用的知识,网上大多数文章都是关于属性动画的用法,本文从源码角度去分析一下属性动画的原理
属性动画有两个非常重要的类,分别是ObjectAnimator和ValueAnimator,其中前者继承了后者,前者是对后者更进一步的封装,方便开发者使用。属性动画常见的用法如下
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) {
//如果第一次保存这个属性的相关值,mValues没被初始化,则创建之
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);
}
}
ofFloat方法三个参数的都很关键,第一个代表动画的作用目标,第二个代表动画目标的指定属性,第三个参数以后是动画值,在此方法中会创建一个ObjectAnimator对象,传入动画目标和属性,然后通过setFloatValues设置动画值,将属性和动画值保存到mValues中,其中mValues是一个PropertyValuesHolder数组,PropertyValuesHolder又是什么?看起来像是将属性和动画值保存在一个类中,来看看
public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
return new FloatPropertyValuesHolder(property, values);
}
//下一步代码
public FloatPropertyValuesHolder(Property property, float... values) {
//将property赋值给mProperty
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就是用来保存相关属性值的,来看看KeyframeSet.ofFloat(values)方法
// 通过这个方法去保存该属性对应的动画值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封装成FloatKeyframes保存在数组中。其中Keyframe我们翻译叫关键帧,用来保存动画执行过程中的一些重要的值,比如开始、结束、中间值等等。这些值在动画执行过程中都会用到
将属性和动画值封装成PropertyValuesHolder之后,接下来看看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];
//将封装好的PropertyValuesHolder保存到一个Map中
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
将封装好的PropertyValuesHolder保存到一个HashMap中,其中key为属性名,当然这个setValues方法是当mValues为null的时候调用的,其实是代表第一次保存属性值,否则调用父类的setFloatValues方法,如下
public void setFloatValues(float... values) {
if (values == null || values.length == 0) {
return;
}
if (mValues == null || mValues.length == 0) {
setValues(PropertyValuesHolder.ofFloat("", values));
} else {
//更新属性对应的动画值
PropertyValuesHolder valuesHolder = mValues[0];
valuesHolder.setFloatValues(values);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
到这里分析完了ObjectAnimator.ofFloat(targetView, "translationX", 100)方法的整个过程,其实就是将我们设置的属性和动画值保存起来,接下来是设置插值器和估值器
二、setInterpolator、setEvaluator和setDuration
//保存插值器
@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);
}
}
//设置动画时长
@Override
public ValueAnimator setDuration(long duration) {
if (duration < 0) {
throw new IllegalArgumentException("Animators cannot have negative duration: " +
duration);
}
mDuration = duration;
return this;
}
插值器和动画时长保存在ValueAnimator中,而估值器保存在PropertyValuesHolder中
相关的值已经设置好了,下面将进入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)
--------------------------------------------
1.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);
}
//callback其实是ValueAnimator
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
先来看getProvider().postFrameCallback(mFrameCallback)方法,其中参数mFrameCallback如下
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
//重复调用
getProvider().postFrameCallback(this);
}
}
};
我暂且不知道mFrameCallback会什么时候执行,但发现里面会重复执行这个回调,其中doAnimationFrame有点像绘制动画帧的方法,再来看看getProvider方法吧
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
//getProvider().postFrameCallback方法最终会执行mChoreographer的postFrameCallback
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
发现是这个类Choreographer承接了mFrameCallback,又是一串长长的调用
//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);
}
//第二步,callback是action
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;
//到这里将mFrameCallback添加到一个数组中保存起来,其中callbackTye为CALLBACK_ANIMATION
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);
}
}
}
程序又走了几步,将mFrameCallback保持到一个数组中,然后执行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 doScheduleVsync() {
synchronized (mLock) {
if (mFrameScheduled) {
scheduleVsyncLocked();
}
}
}
//第二步
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
//第三步
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方法,呵呵了?native方法的参数mReceiverPtr是一个指向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);
}
因为obtain方法的第二个参数传递this,所以这里将通过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();
//类型CALLBACK_ANIMATION就是最开始保存的mFrameCallback
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);
}
……
}
doFrame的关键是开始执行各种类型的callback了,进入去看看
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,到这里最开始保存那个mFrameCallback就已经开始执行了
private void postCallbackDelayedInternal(int callbackType,
...................
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
//mFrameCallback就在这里保存到数组的
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();
}
}
}
饶了一大圈,终于到了执行mFrameCallback的doFrame方法了,我们回过头去看看mFrameCallback的代码
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
//重复调用
getProvider().postFrameCallback(this);
}
}
};
可以看到,doFrame方法就会被重复执行,然后通过doAnimationFrame来绘制动画,接下来看看它是如何绘制的
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)
来看看ValueAnimator中的接口实现
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;
//通过fraction计算mValues中保存的各个动画值
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);
}
}
}
这里利用了之前设置的的插值器,通过插值器获得动画的执行进度,然后计算各种动画值,回调我们在ValueAnimator中设置的监听方法,比如下面的
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
});
上面从animateValue开始分析的其实是ValueAnimator的相关实现,但是我们刚开始的例子是用ObjectAnimator实现动画的,而ObjectAnimator是继承ValueAnimator的,而且它也重写了animateValue方法,下面来分析一下ObjectAnimator的动画实现是怎么样的
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);
}
}
除了调用父类的animateValue,还遍历执行了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()方法吧
2.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(); //调用FloatPropertyValuesHolder的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);
}
}
好像没什么值得的发现,我们来看看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;
}
这里会通过mJniSetter指针,修改动画目标对应的属性值,比如例子中的view.setTranslateX(value)方法。代码到这里,我们完成了view属性的更新,整个动画过程中,随着动画的进度不断改变,属性值也会不断改变,然后就不断调用View是属性的set方法,在View的set方法中将会不断刷新渲染View,从而呈现出动画的效果 那现在改变了动画目标的属性值,接下来自然就想到了是目标View的渲染操作了,只有最后渲染了才能呈现出动画的效果
通过了上面可以动画的所有条件都已经准备好了,mJnisSetter指针也可以准备好了,那么就剩下最后一个方法setCurrentPlayTime了,此方法是指定动画从什么时间点开始执行,所以一开始我们传参为0,通过这个方法,动画将从0开始执行
3.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的更新操作,代表动画的开始
四、总结
整个过程还是挺长的,来总结一下动画执行的整体过程
1.设置属性动画的目标、属性、动画值、插值器、估值器、动画时长等等
2.设置好以后,即开始动画,分为三个阶段
第一阶段是添加动画回调,这里会实现一个循环重复调用绘制动画的操作
第二阶段是开始动画,主要是通过各种属性和值,最终不断改变动画目标的属性值,从而实现动画效果
第三阶段是指定动画开始指定的时间
3.动画结束