本篇文章通过源码介绍属性动画。不废话先看下图,根据下图顺序查看源码。
##ObjectAnimator
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
//创建ObjectAnimator 对象并设置target和propertyName
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
//调用了父类的setFloatValues(values)方法
anim.setFloatValues(values);
return anim;
}
private ObjectAnimator(Object target, String propertyName) {
setTarget(target);
setPropertyName(propertyName);
}
@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);
}
}
##ValueAnimator为ObjectAnimator的父类
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];
//设置动画属性。ofFloat()方法到此就结束了
valuesHolder.setFloatValues(values);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
##PropertyValuesHolder
public void setFloatValues(float... values) {
mValueType = float.class;
mKeyframes = KeyframeSet.ofFloat(values);
}
##KeyframeSet
public static KeyframeSet ofFloat(float... values) {
...
return new FloatKeyframeSet(keyframes);
}
总结:
1、创建ObjectAnimator对象,保存target和propertyName。
2、根据传入的values创建一组关键帧。
3、关键帧封装到FloatPropertyValuesHolder中。
4、FloatPropertyValuesHolder交给mValues和mValuesMap持有。
接下来看看start()方法。
##ObjectAnimator
@Override
public void start() {
AnimationHandler.getInstance().autoCancelBasedOn(this);
...
super.start();//调用父类的start()方法
}
##ValueAnimator
@Override
public void start() {
start(false);
}
private void start(boolean playBackwards) {
...
addAnimationCallback(0);//为向系统注册垂直同步信号
...
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);
}
}
}
先看看是如何注册垂直同步信号的。
##ValueAnimator
private void addAnimationCallback(long delay) {
...
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
##AnimationHandler
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
//创建MyFrameCallbackProvider 并调用postFrameCallback方法
getProvider().postFrameCallback(mFrameCallback);
}
...
}
private AnimationFrameCallbackProvider getProvider() {
if (mProvider == null) {
mProvider = new MyFrameCallbackProvider();
}
return mProvider;
}
private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
//通过一系列的判断调用并最终调用native层
mChoreographer.postFrameCallback(callback);
}
...
}
##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) {
...
scheduleFrameLocked(now);
...
}
private void scheduleFrameLocked(long now) {
...
scheduleVsyncLocked();
...
}
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
##DisplayEventReceiver
public void scheduleVsync() {
...
nativeScheduleVsync(mReceiverPtr);
...
}
//native 完成垂直同步信号的注册
//该方法通过jni层回调到DisplayEventReceiver类的onVsync方法中,该类为抽象类
//onVsync为空实现方法具体由子类实现。
@FastNative
private static native void nativeScheduleVsync(long receiverPtr);
##Choreographer
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
...
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
...
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
Log.d(TAG, "Received vsync from secondary display, but we don't support "
+ "this case yet. Choreographer needs a way to explicitly request "
+ "vsync for a specific display to ensure it doesn't lose track "
+ "of its scheduled vsync.");
scheduleVsync();
return;
}
...
@Override
public void run() {
mHavePendingVsync = false;
//接收到系统jni层回调
doFrame(mTimestampNanos, mFrame);
}
}
void doFrame(long frameTimeNanos, int frame) {
...
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);
...
}
void doCallbacks(int callbackType, long frameTimeNanos) {
//定义内部类CallbackRecord并循环调用run方法
CallbackRecord callbacks;
...
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));
}
c.run(frameTimeNanos);
}
...
}
##Choreographer.CallbackRecord
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
public Object action; // Runnable or FrameCallback
public Object token;
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
##AnimationHandler
//接收并实现回调
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
//动画未结束并再次循环调用
getProvider().postFrameCallback(this);
}
}
};
##AnimationHandler
private void doAnimationFrame(long frameTime) {
long currentTime = SystemClock.uptimeMillis();
final int size = mAnimationCallbacks.size();
for (int i = 0; i < size; i++) {
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
if (isCallbackDue(callback, currentTime)) {
//回调到ValueAnimator 中并设置属性
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
cleanUpList();
}
##ValueAnimator implements AnimationHandler.AnimationFrameCallback
public final boolean doAnimationFrame(long frameTime) {
...
boolean finished = animateBasedOnTime(currentTime);
...
return finished;
}
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
...
animateValue(currentIterationFraction);
return done;
}
@CallSuper
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);
}
}
}
总结:
start方法中的addAnimationCallback此方法从底层注册垂直同步信号,通过层层回调设置跟新属性。
再来看看 start方法中的setCurrentPlayTime(0)。
##ValueAnimator
public void setCurrentPlayTime(long playTime) {
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
public void setCurrentFraction(float fraction) {
initAnimation();
...
animateValue(currentIterationFraction);
}
@CallSuper
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);
}
}
}
##ObjectAnimator
@CallSuper
@Override
void animateValue(float fraction) {
final Object target = getTarget();
if (mTarget != null && target == null) {
// We lost the target reference, cancel and clean up. Note: we allow null target if the
/// target has never been set.
cancel();
return;
}
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//调用父类中的mValues数组并调用setAnimatedValue
mValues[i].setAnimatedValue(target);
}
}
##PropertyValuesHolder
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());
}
}
}
总结:
属性动画是通过反射来改变对象的属性值。并调用方法。
本篇文章到这里就结束了!
作者:Dean_Xu
原创博客,请注明转载处....