版权声明:本文为博主原创文章,未经博主允许不得转载。
本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。
这是是根据 API 25 进行 ObjectAnimator 的使用代码分析。
public void startAnimator(View view){
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f);
objectAnimator.setDuration(500);
objectAnimator.start();
}
一、ofFloat
ObjectAnimator 的 ofFloat:
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
在这里,他先 new 了一个 ObjectAnimator,跟进去查看一下:调用了 setTarget 和 setPropertyName 方法。
private ObjectAnimator(Object target, String propertyName) {
setTarget(target);
setPropertyName(propertyName);
}
很明显,setTarget 设置的是该属性动画的执行对象是谁,setPropertyName 设置要执行的是什么属性。
ObjectAnimator 的 setTarget:
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;
}
}
在 setTarget 中把要执行动画的对象存在成员变量 mTarget 中,这边采用的是弱引用,可以有效的避免内存泄漏。同样的,在 setPropertyName 中把执行动画的属性存在成员变量 mProperty 中。
继续 ofFloat 往下,调用了 ObjectAnimator 的 setFloatValues 方法。
ObjectAnimator 的 setFloatValues:
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);
}
}
正常情况下, mValues 是不会为空的,走 else,调用 ValueAnimator 的 setFloatValues 方法。
ValueAnimator 的 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;
}
在 ValueAnimator 的 setFloatValues 中,使用了一个 PropertyValuesHolder 这个类,第一次调用 mValues 是空的,调用 PropertyValuesHolder.ofFloat("", values)。一直点下去,最终也跟 else 一样调用了 PropertyValuesHolder 的 setFloatValues 方法。
PropertyValuesHolder 的 setFloatValues:
public void setFloatValues(float... values) {
//设置值类型
mValueType = float.class;
//设置关键帧
mKeyframes = KeyframeSet.ofFloat(values);
}
直接设置值类型 mValueType 为 float 类型,可以猜想,如果是 setIntValues ,那值类型 mValueType 设置为 int。
mKeyframes 是存放关键帧,关键帧在初始时候传入属性值变化的范围(下放代码 0f 和 200f 即关键帧)
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f);
当传入多个的时候,关键帧也将变成多个。下方关键帧有 4 个,变化区间有三个,如果动画执行时间是 300ms,则每个区间的执行时间将均匀分配为 100ms。(为什么平均分配,后面看到再提)
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f, 500f, 400f);
KeyframeSet 的 ofFloat:
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
int numKeyframes = values.length;
//FloatKeyframe 是一个接口,在这 new 了一个 FloatKeyframe 数组
//关键帧只有一个的时候,默认加一个 0f
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) {
//(float) i / (numKeyframes - 1) 则是为了将时间均分
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);
}
在这边,判断关键帧的个数,当关键帧只有一个的时候,添加一个 0f 的关键帧,所以,下面两行代码效果是一致的:
ObjectAnimator.ofFloat(view,"translationX", 1f);
ObjectAnimator.ofFloat(view,"translationX", 0f, 1f);
中间先不管,最终是返回了一个 new FloatKeyframeSet(keyframes),在这里直接调用 super(keyframes), FloatKeyframeSet 的父类是 KeyframeSet ,即又调回到 KeyframeSet 的构造方法。
KeyframeSet 的构造方法:
public KeyframeSet(Keyframe... keyframes) {
mNumKeyframes = keyframes.length;
// immutable list
//保存所有帧
mKeyframes = Arrays.asList(keyframes);
//设置第一帧
mFirstKeyframe = keyframes[0];
//设置最后一帧
mLastKeyframe = keyframes[mNumKeyframes - 1];
mInterpolator = mLastKeyframe.getInterpolator();
}
顺便查看一下 KeyframeSet 的其他成员变量,可以发现,KeyframeSet 还保存有估值器和插值器。
总结: ObjectAnimator 的 ofFloat 方法主要做一些初始化操作,新建了一个 ObjectAnimator 对象,保存了要执行动画的对象和属性,并对关键帧进行了解析。
二、start
1.回调
接下来继续看一下 ObjectAnimator 的 start 方法。
ObjectAnimator 的 start:
public void start() {
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();
}
中间一些处理忽略,最终调用了 super.start(),ObjectAnimator 的父类是 ValueAnimator,即调用了 ValueAnimator的 start。
ValueAnimator 的 start:
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mReversing = playBackwards;
// 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 = 0;
AnimationHandler animationHandler = AnimationHandler.getInstance();
animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
if (mStartDelay == 0 || mSeekFraction >= 0) {
// 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);
}
}
}
这里使用了一个 animationHandler,通过广播的机制由底层进行回调,每 16ms 进行一次回调。(再下去就比较底层了,涉及到垂直刷新,不继续了)
继续查看 AnimationHandler 的 addAnimationFrameCallback 方法。
AnimationHandler 的 addAnimationFrameCallback:
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
//再分析下去比较复杂,总之广播接收到会调用 mFrameCallback。
getProvider().postFrameCallback(mFrameCallback);
}
//保存回调
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
我们看一下变量 mFrameCallback,回调的时候调用了 doAnimationFrame 方法。getProvider().getFrameTime() 获取的当前动画执行的真正时间。
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 的 doAnimationFrame:
private void doAnimationFrame(long frameTime) {
int size = mAnimationCallbacks.size();
long currentTime = SystemClock.uptimeMillis();
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 是由 ValueAnimator 中传递过来的 this,即 ValueAnimator 本身。ValueAnimator 的 doAnimationFrame 方法会调用 startAnimation 方法,跟 ObjectAnimator 的 start 一样。
2.反射方法
继续 ValueAnimator 的 start 方法,接下去直接调用 startAnimation() 启动动画,
ValueAnimator 的 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() 进行一些初始化操作,这边要注意一点的是,我们在这边分析的 ObjectAnimator 的源码,ObjectAnimator 有对 initAnimation 方法进行重写。
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 是父类 ValueAnimator 的属性,是 PropertyValuesHolder
mValues[i].setupSetterAndGetter(target);
}
}
super.initAnimation();
}
}
ObjectAnimator 的 initAnimation 调用了 PropertyValuesHolder 的 setupSetterAndGetter 方法。
PropertyValuesHolder 的 setupSetterAndGetter:
void setupSetterAndGetter(Object target) {
...
Class targetClass = target.getClass();
if (mSetter == null) {
setupSetter(targetClass);
}
...
}
PropertyValuesHolder 的 setupSetter:
void setupSetter(Class targetClass) {
Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
//传入 set,反射生成 set 方法。
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
}
PropertyValuesHolder 的 setupSetterOrGetter:
private Method setupSetterOrGetter(Class targetClass,
HashMap<Class, HashMap<String, Method>> propertyMapMap,
String prefix, Class valueType) {
...
setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
...
}
return setterOrGetter;
}
PropertyValuesHolder 的 getPropertyFunction:
private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
// TODO: faster implementation...
Method returnVal = null;
String methodName = getMethodName(prefix, mPropertyName);
Class args[] = null;
if (valueType == null) {
try {
returnVal = targetClass.getMethod(methodName, args);
} catch (NoSuchMethodException e) {
// Swallow the error, log it later
}
} else {
...
}
return returnVal;
}
PropertyValuesHolder 的 getPropertyFunction 最终通过反射生产对应的 set 或 get 方法并返回。
在这边顺便提一下 getMethodName 方法。
PropertyValuesHolder 的 getMethodName:
static String getMethodName(String prefix, String propertyName) {
if (propertyName == null || propertyName.length() == 0) {
// shouldn't get here
return prefix;
}
char firstLetter = Character.toUpperCase(propertyName.charAt(0));
String theRest = propertyName.substring(1);
return prefix + firstLetter + theRest;
}
getMethodName 方法对传入的方法名进行首字母修改为大写处理,所以在传属性的时候,首字母大小写是没有影响的。下方两行代码效果一样:
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "TranslationX", 0f, 200f);
ObjectAnimator 的 initAnimation 在最后调用了 super.initAnimation(),即 ValueAnimator 的 initAnimation 方法。
ValueAnimator 的 initAnimation :
void initAnimation() {
if (!mInitialized) {
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].init();
}
mInitialized = true;
}
}
mValues[i].init() 调用了 PropertyValuesHolder 的 init,在这里进行了估值器的设置。
总结: 到这里,PropertyValuesHolder 的成员变量 mSetter 为对应属性的 set 方法。
3.方法的调用
再次回到 ValueAnimator 的 start 继续向下。
ValueAnimator 的 start :
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 的 setCurrentPlayTime :
public void setCurrentPlayTime(long playTime) {
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
所以,ObjectAnimator 的 start 最终调用到了 setCurrentFraction 方法,传入的是动画执行的的百分比。在 setCurrentFraction 方法里面调用了 animateValue 方法。注意,ValueAnimator 也重写了该方法。
ObjectAnimator 的 animateValue :
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);
}
}
ObjectAnimator 的 animateValue 调用了 super.animateValue(fraction), 在这里进行了插值器的使用。
最后调用了 mValues[i].setAnimatedValue(target),即 PropertyValuesHolder 的 setAnimatedValue 方法。
PropertyValuesHolder 的 setAnimatedValue:
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());
}
}
}
在这里进行前面反射的方法的调用,即我们设置的属性的 set 方法的调用,每次底层回调都会进行一次重新调用改属性的 set 方法进行设置,从而达到动画的效果。