android animator 简书,Android ObjectAnimator源码不一样的分析

1.前言

最近在看项目代码中,突然冒出这样一个想法:如果在ObjectAnimator动画结束回调函数onAnimationEnd中重新start此动画,是否能达到循环播放动画呢?其实通过setRepeatCount()和setRepeatMode()函数配合使用也是可以实现动画循环播放的效果,但是出于好奇,我还是想通过代码实现来验证自己的想法,代码如下:

final ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(target, "scaleX", 1.0f, 2.0f)

.setDuration(5000);

objectAnimator.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

Log.d("MainActivity", "onAnimationStart");

}

@Override

public void onAnimationEnd(Animator animator) {

Log.d("MainActivity", "onAnimationEnd");

objectAnimator.start();

}

@Override

public void onAnimationCancel(Animator animation) {

Log.d("MainActivity", "onAnimationCancel");

}

@Override

public void onAnimationRepeat(Animator animation) {

Log.d("MainActivity", "onAnimationRepeat");

}

});

objectAnimator.start();

通过代码实验,惊奇地发现,动画并没有达到我预期的效果,这个渐显动画只是播放了两次而已,且在第二次动画过程中没有onAnimationStart和onAnimationEnd方法的回调。

这是为什么呢?由此激起了我对ObjectAnimator源码实现的兴趣。在这边博客中,主要分析ObjectAnimator动画实现机制以及ObjectAnimator在Duration时间内是如何更新Target属性值,希望对感兴趣的同学有一些帮助。

2.基本使用

ObjectAnimator

.ofFloat(button, "alpha", 0.0f, 1.0f)

.setDuration(5000)

.start();

3.深入分析

3.1 从ObjectAnimator.ofFloat()开始

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {

ObjectAnimator anim = new ObjectAnimator(target, propertyName);

anim.setFloatValues(values);

return anim;

}

这个静态方法会创建一个ObjectAnimator对象,在构造时同时设置属性动画的目标target和作用于target的属性名propertyName,根据上面的例子,target为button,propertyName为alpha。

3.1.1 ObjectAnimator构造函数

private ObjectAnimator(Object target, String propertyName) {

setTarget(target);

setPropertyName(propertyName);

}

在ObjectAnimator构造函数中分别调用了setTarget和setPropertyName方法

3.1.2 下面我们来分析ObjectAnimator.setTarget()方法

@Override

public void setTarget(@Nullable Object target) {

final Object oldTarget = getTarget();

if (oldTarget != target) {

if (isStarted()) {

cancel();

}

mTarget = target == null ? null : new WeakReference(target);

// New target should cause re-initialization prior to starting

// 记录尚未初始化,ValueAnimator的初始化标志位

mInitialized = false;

}

}

从源码中,我们可以分析出两点:

当oldTarget不等于target,且已经调用了start()方法使得mStarted标志位为true时,需要先cancel掉此动画,进入ValueAnimator.cancel()函数,你会发现,系统会先遍历mLiseners调用AnimatorLisener.onAnimatorCancel()函数,接着调用ObjectAnimator.endAnimation函数,最后遍历mLiseners调用AnimatorLisener.onAnimatorEnd()函数。这里矫正了我之前的一个误区,不知道你之前是否也这样的误区,在调用ObjectAnimtor.cancel()动画时,不仅仅会回调AnimatorLisener.onAnimatorCancel()方法,还会回调AnimatorLisener.onAnimatorEnd()方法;

mTarget是一个软引用,而不是一个强引用哦,这样ObjectAnimator就不会持有View的引用,不会影响Activity的正常回收,从而不会引起Activity内存泄漏。

3.1.3 接着分析ObjectAnimator.setPropertyName()方法

回到ObjectAnimator构造函数中,setPropertyName方法设置属性名称,即为alpha

// 设置属性名称,也就是上面设置的”alpha"

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.

// mValues是一个数组,用于保存PropertyValuesHolder

if (mValues != null) {

// 属性值得更新操作委托给PropertyValuesHolder进行

// Animator只进行数值计算

PropertyValuesHolder valuesHolder = mValues[0];

String oldName = valuesHolder.getPropertyName();

// 更新第一个PropertyValuesHolder的PropertyName

valuesHolder.setPropertyName(propertyName);

mValuesMap.remove(oldName);

mValuesMap.put(propertyName, valuesHolder);

}

mPropertyName = propertyName;

// New property/values/target should cause re-initialization prior to starting

// 记录尚未初始化,ValueAnimator的标志位

mInitialized = false;

}

回到ObjectAnimator.OfFloat()方法中,还有一步就是调用ObjectAnimator.setFloatValues()方法

3.1.4 ObjectAnimator.setFloatValues()方法

@Override

public void setFloatValues(float... values) {

// 第一次调用时,values为null

if (mValues == null || mValues.length == 0) {

// No values yet - this animator is being constructed piecemeal. Init the values with

// whatever the current propertyName is

// 我们设置了mPropertyName,在这里mProperty为null

if (mProperty != null) {

setValues(PropertyValuesHolder.ofFloat(mProperty, values));

} else {

setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));

}

} else {

super.setFloatValues(values);

}

}

在setValues之前先调用PropertyValuesHolder.ofFloat(mPropertyName, values)方法初始化PropertyValuesHolder对象

3.1.5 PropertyValuesHolder.ofFloat方法

// 静态方法构造FloatPropertyValuesHolder

public static PropertyValuesHolder ofFloat(String propertyName, float... values) {

return new FloatPropertyValuesHolder(propertyName, values);

}

调用FloatPropertyValuesHolder构造方法

// FloatPropertyValuesHolder构造方法

public FloatPropertyValuesHolder(String propertyName, float... values) {

super(propertyName);

// 调用FloatPropertyValuesHolder.setFloatValues方法

setFloatValues(values);

}

调用FloatPropertyValuesHolder的setFloatValues()方法

// FloatPropertyValuesHolder

@Override

public void setFloatValues(float... values) {

// 调用PropertyValuesHolder.setFloatValues方法

super.setFloatValues(values);

mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;

}

调用父类PropertyValuesHolder的setFloatValues()方法初始化关键帧集合

// PropertyValuesHolder.setFloatValues

public void setFloatValues(float... values) {

// 记录mValueType值,便于使用反射方式遍历获取目标target对应的set和get方法

// 具体可以看getPropertyFunction方法

mValueType = float.class;

mKeyframes = KeyframeSet.ofFloat(values);

}

然后设置mKeyframes,KeyFrame是属性动画中的关键帧,通过设置关键帧来保证动画执行的时序性

3.1.6 KeyframeSet.ofFloat()方法

// 静态方法KeyframeSet.ofFloat

public static KeyframeSet ofFloat(float... values) {

boolean badValue = false;

int numKeyframes = values.length;

// 至少初始化两个关键帧

FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];

// 如果values只有一个数值时,那么只有开始和结束这两个关键帧

if (numKeyframes == 1) {

keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);

// 当values只有一个数值时,作为结束帧

keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);

// 判断values中的数值是否是有效值

if (Float.isNaN(values[0])) {

badValue = true;

}

} else {

// 给values中的每一个数值都设置一个关键帧

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;

}

}

}

// 当values数值不是有效值时,打印出日志,但是不做其他处理

if (badValue) {

Log.w("Animator", "Bad value (NaN) in float animator");

}

return new FloatKeyframeSet(keyframes);

}

接下来我们看一下关键帧Keyframe是如何创建的

public static Keyframe ofFloat(float fraction, float value) {

return new FloatKeyframe(fraction, value);

}

在FloatKeyFrame构造函数中保存fraction和value等值

FloatKeyframe(float fraction, float value) {

mFraction = fraction;

mValue = value;

mValueType = float.class;

mHasValue = true;

}

KeyFrame其实只是对当前的fraction和value做了一个保存作用,mValueType就是根据不同类型的KeyFrame设置不同的值,这里设置了float.class值

KeyFrame下面,我们接着看KeyframeSet.ofFloat方法,最终会创建一个关键帧的集合FloatKeyframeSet

public FloatKeyframeSet(FloatKeyframe... keyframes) {

// 调用父类KeyframeSet的构造方法

super(keyframes);

}

public KeyframeSet(Keyframe... keyframes) {

mNumKeyframes = keyframes.length;

// immutable list

mKeyframes = Arrays.asList(keyframes);

mFirstKeyframe = keyframes[0];

mLastKeyframe = keyframes[mNumKeyframes - 1];

mInterpolator = mLastKeyframe.getInterpolator();

}

ObjectAnimator.ofFloat的过程就结束了,下面我们一起来看其他方法

3.2 分析ObjectAnimator.setDuration()方法

setDuration()用于设置动画执行的时间,这个方法比较简单

public ValueAnimator setDuration(long duration) {

// 检查duration,小于零则抛出异常

if (duration < 0) {

throw new IllegalArgumentException("Animators cannot have negative duration: " +

duration);

}

// 使用mUnscaledDuration保存未做缩放的动画执行时间

mUnscaledDuration = duration;

// 计算经过缩放的动画执行时间,默认情况下mDuration=duration

updateScaledDuration();

return this;

}

3.3 ObjectAnimator.setInterpolator()方法

setInterpolator()设置动画执行时使用到的插值器,默认的插值器是带有加减速度的插值器

// The time interpolator to be used if none is set on the animation

private static final TimeInterpolator sDefaultInterpolator =

new AccelerateDecelerateInterpolator();

@Override

public void setInterpolator(TimeInterpolator value) {

if (value != null) {

mInterpolator = value;

} else {

// value为空时,使用线性插值器

mInterpolator = new LinearInterpolator();

}

}

3.4 接下分析ObjectAnimator.start()方法

start()方法是ObjectAnimator中最重要的一个方法,控制着属性动画的启动,这里是见证奇迹的地方,不管你会不会激动,反正我是激动了。

3.4.1 从ObjectAnimator.start()方法开始

@Override

public void start() {

// See if any of the current active/pending animators need to be canceled

AnimationHandler handler = sAnimationHandler.get();

// 第一次启动,handler为空

if (handler != null) {

// 通过遍历mAnimations队列来cancel当前动画

int numAnims = handler.mAnimations.size();

for (int i = numAnims - 1; i >= 0; i--) {

if (handler.mAnimations.get(i) instanceof ObjectAnimator) {

ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);

if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {

anim.cancel();

}

}

}

// 通过遍历mPendingAnimations队列来cancel当前动画

numAnims = handler.mPendingAnimations.size();

for (int i = numAnims - 1; i >= 0; i--) {

if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {

ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);

if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {

anim.cancel();

}

}

}

// 通过遍历mDelayedAnims队列来cancel当前动画

numAnims = handler.mDelayedAnims.size();

for (int i = numAnims - 1; i >= 0; i--) {

if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {

ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);

if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {

anim.cancel();

}

}

}

}

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));

}

}

// 转到ValueAnimator的start()方法

super.start();

}

AnimationHandler有三个重要的参数:mAnimations、mPendingAnimations以及mDelayedAnims,具体如下:

mAnimations是一个用来保存当前正在执行的动画列表,

mPendingAnimation是一个用来保存已经调用了start(boolean playBackwards)方法加入进来的动画列表,不管是否设置mStartDelay延迟时间,都会加入到此列表中

mDelayedAnims是一个用来保存设置了mStartDelay延迟时间的动画列表,mStartDelay要大于零

3.4.2 最终调用到ValueAnimator.start(boolean playBackwards)方法

// playBackwards表示是否倒序播放,这里我们传入的是false

private void start(boolean playBackwards) {

if (Looper.myLooper() == null) {

throw new AndroidRuntimeException("Animators may only be run on Looper threads");

}

mReversing = playBackwards;

mPlayingBackwards = playBackwards;

// 此时playBackwards为false,第一次启动动画时mSeekFraction为-1,不会进入

if (playBackwards && mSeekFraction != -1) {

if (mSeekFraction == 0 && mCurrentIteration == 0) {

// special case: reversing from seek-to-0 should act as if not seeked at all

mSeekFraction = 0;

} else if (mRepeatCount == INFINITE) {

mSeekFraction = 1 - (mSeekFraction % 1);

} else {

mSeekFraction = 1 + mRepeatCount - (mCurrentIteration + mSeekFraction);

}

mCurrentIteration = (int) mSeekFraction;

mSeekFraction = mSeekFraction % 1;

}

if (mCurrentIteration > 0 && mRepeatMode == REVERSE &&

(mCurrentIteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) {

// if we were seeked to some other iteration in a reversing animator,

// figure out the correct direction to start playing based on the iteration

if (playBackwards) {

mPlayingBackwards = (mCurrentIteration % 2) == 0;

} else {

mPlayingBackwards = (mCurrentIteration % 2) != 0;

}

}

int prevPlayingState = mPlayingState;

mPlayingState = STOPPED;

// 在调用start方法之后,mStarted状态改为true

mStarted = true;

mStartedDelay = false;

mPaused = false;

updateScaledDuration(); // in case the scale factor has changed since creation time

AnimationHandler animationHandler = getOrCreateAnimationHandler();

// 把当前动画加入到animationHandler.mPendingAnimation队列中

animationHandler.mPendingAnimations.add(this);

// 此处启动动画,等一下分析

if (mStartDelay == 0) {

// This sets the initial value of the animation, prior to actually starting it running

if (prevPlayingState != SEEKED) {

// 第一次启动,设置当前启动时间为0

setCurrentPlayTime(0);

}

mPlayingState = STOPPED;

mRunning = true;

// 回调AnimatorListener.onAnimationStart()方法通知用户

notifyStartListeners();

}

animationHandler.start();

}

这里代码量有点多,主要是根据是否设置动画循环播放来设置标志位和状态,在start方法中调用ValueAnimator.setCurrentPlayTime()方法来设置动画的播放时间

3.4.3 紧接着进入ValueAnimator.setCurrentPlayTime()方法

// ValueAnimator

public void setCurrentPlayTime(long playTime) {

// mUnscaledDuration就是我们设置的动画执行时间,这里为5000毫秒

// 第一次执行时,我们的playTime传进来就是0

float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1;

// 第一次执行时,fraction=0,调用ValueAnimator.setCurrentFraction()方法

setCurrentFraction(fraction);

}

3.4.4 调用到ValueAnimator.setCurrentFraction()方法

接下来一起进入setCurrentFraction(float fraction)方法

public void setCurrentFraction(float fraction) {

// 接下来马上分析

initAnimation();

// 此时传进来的fraction=0

if (fraction < 0) {

fraction = 0;

}

int iteration = (int) fraction;

// 循环动画时才会进入

if (fraction == 1) {

iteration -= 1;

} else if (fraction > 1) {

if (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE) {

if (mRepeatMode == REVERSE) {

mPlayingBackwards = (iteration % 2) != 0;

}

fraction = fraction % 1f;

} else {

fraction = 1;

iteration -= 1;

}

} else {

mPlayingBackwards = mReversing;

}

mCurrentIteration = iteration;

// 默认情况下,sDurationScale为1.0f,这里mDuration就是我们设置的动画执行时间5000ms

long seekTime = (long) (mDuration * fraction);

// 获取当前动画执行的时间点

long currentTime = AnimationUtils.currentAnimationTimeMillis();

// 计算当前动画已经执行的时长

mStartTime = currentTime - seekTime;

mStartTimeCommitted = true; // do not allow start time to be compensated for jank

if (mPlayingState != RUNNING) {

mSeekFraction = fraction;

mPlayingState = SEEKED;

}

if (mPlayingBackwards) {

fraction = 1f - fraction;

}

animateValue(fraction);

}

从上面的代码分析来看,其中调用到了两个方法,分别是initAnimation()和animateValue(fraction)方法

3.4.5 我们先来看ObjectAnimator.initAnimation()方法

@Override

// ObjectAnimator

void initAnimation() {

// 第一次执行时,mInitialized为false,初始化后该标志位置为true,可以避免多次init

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) {

// 执行PropertyValuesHolder的setupSetterAndGetter()方法

mValues[i].setupSetterAndGetter(target);

}

}

super.initAnimation();

}

}

3.4.6 分析PropertyValuesHolder.setupSetterAndGetter()

PropertyValuesHolder.setupSetterAndGetter(Object target)方法,主要是初始化反射方法mSetter和mGetter

// PropertyValuesHolder

void setupSetterAndGetter(Object target) {

mKeyframes.invalidateCache();

// 按照上面的例子,我们设置的是mPropertyName,mProperty为null,不会进去

if (mProperty != null) {

// check to make sure that mProperty is on the class of target

try {

Object testValue = null;

List 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.

// mProperty为空,判断get和set方法是否存在

if (mProperty == null) {

Class targetClass = target.getClass();

if (mSetter == null) {

// 查找目标属性的set方法,初始化mSetter方法

setupSetter(targetClass);

}

// 遍历关键帧集合

List 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) {

// 查找目标属性的get方法,初始化mGetter方法

setupGetter(targetClass);

// mGetter为null时,直接return

if (mGetter == null) {

// Already logged the error - just return to avoid NPE

return;

}

}

try {

// 通过mGetter反射获取属性值

Object value = convertBack(mGetter.invoke(target));

// 初始化关键帧Keyframe的mValue值

kf.setValue(value);

// 设置Keyframe标志位为true,表示已经初始化mValue

kf.setValueWasSetOnStart(true);

} catch (InvocationTargetException e) {

Log.e("PropertyValuesHolder", e.toString());

} catch (IllegalAccessException e) {

Log.e("PropertyValuesHolder", e.toString());

}

}

}

}

}

在上面代码中调用到setupSetter和setupGetter方法,这个两个方法最终都是调用setupSetterOrGetter方法

3.4.7 分析PropertyValuesHolder.setupSetterOrGetter()

// 参数prefix值为“set”或者“get”,在这里valueType为float.class

private Method setupSetterOrGetter(Class targetClass,

HashMap> propertyMapMap,

String prefix, Class valueType) {

Method setterOrGetter = null;

// 进行同步锁判断

synchronized(propertyMapMap) {

// Have to lock property map prior to reading it, to guard against

// another thread putting something in there after we've checked it

// but before we've added an entry to it

// 根据targetClass获取HashMap,这个propertyMap是以mPropertyName为key,set或者get方法作为value

// 在这里mPropertyName为"alpha"

HashMap propertyMap = propertyMapMap.get(targetClass);

boolean wasInMap = false;

if (propertyMap != null) {

wasInMap = propertyMap.containsKey(mPropertyName);

if (wasInMap) {

setterOrGetter = propertyMap.get(mPropertyName);

}

}

// 第一次初始化,wasInMap为false

if (!wasInMap) {

// 初始化setterOrGetter

setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);

if (propertyMap == null) {

propertyMap = new HashMap();

propertyMapMap.put(targetClass, propertyMap);

}

propertyMap.put(mPropertyName, setterOrGetter);

}

}

return setterOrGetter;

}

在setupSetterOrGetter方法中调用到了getPropertyFunction函数来初始化mSetter或者mGetter参数

3.4.8 接下来分析PropertyValuesHolder.getPropertyFunction()

private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {

// TODO: faster implementation...

Method returnVal = null;

// 通过prefix和mPropertyName拼接出方法名,如setAlpha或者getAlpha

String methodName = getMethodName(prefix, mPropertyName);

Class args[] = null;

// valueType为Float.class

if (valueType == null) {

try {

returnVal = targetClass.getMethod(methodName, args);

} catch (NoSuchMethodException e) {

// Swallow the error, log it later

}

} else {

args = new Class[1];

Class typeVariants[];

// typeVariants为FLOAT_VARIANTS

if (valueType.equals(Float.class)) {

typeVariants = FLOAT_VARIANTS;

} else if (valueType.equals(Integer.class)) {

typeVariants = INTEGER_VARIANTS;

} else if (valueType.equals(Double.class)) {

typeVariants = DOUBLE_VARIANTS;

} else {

typeVariants = new Class[1];

typeVariants[0] = valueType;

}

// FLOAT_VARIANTS,遍历含有float.class、Float.class、double.class、Double.class等参数的方法

// 只要是相关的基本类型,都会遍历反射查找set或者get方法,看到这里是不是感觉太神奇了

for (Class typeVariant : typeVariants) {

args[0] = typeVariant;

try {

// 反射获取方法,成功则直接返回

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) {

Log.w("PropertyValuesHolder", "Method " +

getMethodName(prefix, mPropertyName) + "() with type " + valueType +

" not found on target class " + targetClass);

}

return returnVal;

}

PropertyValuesHolder.setupSetterAndGetter方法已经分析完毕,回到ObjectAnimator.initAnimation()方法中来,遍历mValues初始化关键帧Keyframe的mSetter、mGetter和初始值,发现还会调用父类ValueAnimator.initAnimation()方法

3.4.9 接下来分析ValueAnimator.initAnimation()

// ValueAnimator.initAnimator方法

void initAnimation() {

if (!mInitialized) {

int numValues = mValues.length;

// 遍历mValues,调用PropertyValuesHolder.init()方法

for (int i = 0; i < numValues; ++i) {

mValues[i].init();

}

mInitialized = true;

}

}

3.4.10 PropertyValuesHolder中的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);

}

}

3.4.11 然后来分析ObjectAnimator.animateValue()方法

ObjectAnimator的initAnimatation过程已经完毕,接下来我们继续回到ValueAnimator.setCurrentFraction(float fraction)方法,最后调用了ObjectAnimator.animateValue(float fraction),这是一个很重要的方法,主要是通过反射的方式来修改目标mTarget的属性值,这里即是alpha值,在后面中会提到,这里可以先记录一下

@Override

// ObjectAnimator

void animateValue(float fraction) {

final Object target = getTarget();

// mTarget是一个软引用,判断target是否已经被回收

if (mTarget != null && target == null) {

// We lost the target reference, cancel and clean up.

cancel();

return;

}

// 这里调用父类ValueAnimator的animateValue来计算数值

super.animateValue(fraction);

int numValues = mValues.length;

for (int i = 0; i < numValues; ++i) {

// 反射修改每一个属性值,这里修改完这一轮动画就结束了

mValues[i].setAnimatedValue(target);

}

}

分析可以看出,如果软引用mTarget已经被回收,就直接调用cancel方法后return,不再执行动画刷新动作;

上面调用父类ValueAnimator中的animateValue方法来进行插值计算

// ValueAnimator

void animateValue(float fraction) {

// 通过插值器进行计算

fraction = mInterpolator.getInterpolation(fraction);

// 获取当前的fraction值

mCurrentFraction = fraction;

int numValues = mValues.length;

for (int i = 0; i < numValues; ++i) {

// 对每一个PropertyValuesHolder计算数值

mValues[i].calculateValue(fraction);

}

if (mUpdateListeners != null) {

int numListeners = mUpdateListeners.size();

for (int i = 0; i < numListeners; ++i) {

// 回调mUpdateListeners监听器

mUpdateListeners.get(i).onAnimationUpdate(this);

}

}

}

回到子类ObjectAnimator的animateValue(float fraction)方法,遍历mValues调用PropertyValuesHolder.setAnimatedValue(target)方法,通过反射方式来修改target的属性值,上面的例子我们是通过PropertyValuesHolder.ofFloat来创建FloatPropertyValuesHolder,那么调用的就是FloatPropertyValuesHolder的setAnimatedValue方法

3.4.12 FloatPropertyValuesHolder.setAnimatedValue

@Override

void setAnimatedValue(Object target) {

// 我们传进来的是mPropertyName

if (mFloatProperty != null) {

mFloatProperty.setValue(target, mFloatAnimatedValue);

return;

}

if (mProperty != null) {

mProperty.set(target, mFloatAnimatedValue);

return;

}

// 针对jni属性

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());

}

}

}

在这里,我们已经把setCurrentPlayTime()方法分析完毕,回到ValueAnimator.start(boolean playBackwards)方法中,最后一行调用到了AnimationHandlers.start()方法,这里是启动动画执行,在mDuration时间内,通过间隔时间来更新目标的属性值,从而实现一系列的动画变化效果。接下来我们一起来分析AnimationHandlers.start()方法,一起来探究是怎么实现在mDuration时间内来实现动画变化效果的。

3.4.13 AnimationHandlers.start()启动动画执行

// AnimationHandlers.start()

public void start() {

scheduleAnimation();

}

// AnimationHandlers.scheduleAnimation()

private void scheduleAnimation() {

if (!mAnimationScheduled) {

mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);

// mAnimationScheduled置为true,控制动画执行,避免在同一帧渲染中重复执行

mAnimationScheduled = true;

}

}

start()方法最终是调用scheduleAnimation()方法,分析scheduleAnimation()方法可以得出,是通过mChoreographer的postCallback方法来启动动画执行的,相当于起了一个定时器来不断更新属性值alpha来实现动画刷新,那么mChoreographer是干嘛的呢,有兴趣的可以去看一下其实现的源码深入了解一下

在这里我简单描述一下,Choreographer这个类是用来控制同步处理输入(Input)、动画(Animation)以及绘制(Draw)三个UI操作的,通过接收显示系统的时间脉冲(垂直同步信号-VSync信号),在下一个Frame渲染时控制执行这些操作。

上面的代码中

mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);

参数mAnimate是一个Runnable,其实是在下一个帧进行渲染时,Choreographer执行这个Runnable(即mAnimate的run方法)

// Called by the Choreographer.

final Runnable mAnimate = new Runnable() {

@Override

public void run() {

// mAnimationScheduled置为false

mAnimationScheduled = false;

doAnimationFrame(mChoreographer.getFrameTime());

}

};

从mAnimate的实现可以看到,最终会调到AnimatationHandlers的doAnimationFrame(long frameTime)方法

3.1.14 分析AnimatationHandlers.doAnimationFrame方法是如何实现动画刷新的

// AnimatationHandlers

void doAnimationFrame(long frameTime) {

mLastFrameTime = frameTime;

// mPendingAnimations holds any animations that have requested to be started

// We're going to clear mPendingAnimations, but starting animation may

// cause more to be added to the pending list (for example, if one animation

// starting triggers another starting). So we loop until mPendingAnimations

// is empty.

// 循环判断mPendingAnimations列表是否有数据

while (mPendingAnimations.size() > 0) {

// 备份mPendingAnimations列表

ArrayList pendingCopy =

(ArrayList) mPendingAnimations.clone();

// 清空mPendingAnimations列表

mPendingAnimations.clear();

int count = pendingCopy.size();

// 遍历pendingCopy

for (int i = 0; i < count; ++i) {

ValueAnimator anim = pendingCopy.get(i);

// If the animation has a startDelay, place it on the delayed list

// animation如果设置了mStartDelay时间,加入到mDelayedAnims队列中 // 以便在下一个Frame渲染时遍历查看mStartDelay时间是否已经到了

if (anim.mStartDelay == 0) {

anim.startAnimation(this);

} else {

mDelayedAnims.add(anim);

}

}

}

// Next, process animations currently sitting on the delayed queue, adding

// them to the active animations if they are ready

int numDelayedAnims = mDelayedAnims.size();

// 遍历mDelayedAnims队列,判断mStartDelay时间是否已经到了,如果是的话则暂存到mReadyAnims队列中

for (int i = 0; i < numDelayedAnims; ++i) {

ValueAnimator anim = mDelayedAnims.get(i);

// 判断anime的mStartDelay时间是否到期

if (anim.delayedAnimationFrame(frameTime)) {

// 把anim加入到mReadyAnims队列中

mReadyAnims.add(anim);

}

}

int numReadyAnims = mReadyAnims.size();

// mReadyAnims保存的就是mDelayedAnims队列中delay时间已经到期的animator,遍历mReadyAnims队列

if (numReadyAnims > 0) {

for (int i = 0; i < numReadyAnims; ++i) {

ValueAnimator anim = mReadyAnims.get(i);

anim.startAnimation(this);

anim.mRunning = true;

mDelayedAnims.remove(anim);

}

// 清空mReadyAnims

mReadyAnims.clear();

}

// Now process all active animations. The return value from animationFrame()

// tells the handler whether it should now be ended

// 把mAnimations队列中的数据备份到mTmpAnimations队列中

int numAnims = mAnimations.size();

for (int i = 0; i < numAnims; ++i) {

mTmpAnimations.add(mAnimations.get(i));

}

// 遍历mTmpAnimations队列

for (int i = 0; i < numAnims; ++i) {

ValueAnimator anim = mTmpAnimations.get(i);

// 判断anim动画是否执行完毕,则加入到mEndingAnims队列中

if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {

mEndingAnims.add(anim);

}

}

// 清空mTmpAnimations

mTmpAnimations.clear();

// 遍历mEndingAnims队列,调用ValueAnimator的endAnimation方法

if (mEndingAnims.size() > 0) {

for (int i = 0; i < mEndingAnims.size(); ++i) {

mEndingAnims.get(i).endAnimation(this);

}

mEndingAnims.clear();

}

// Schedule final commit for the frame.

// 更新ValueAnimator的mStartTime时间,暂时不去看

mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mCommit, null);

// If there are still active or delayed animations, schedule a future call to

// onAnimate to process the next frame of the animations.

// 如果还有动画正在执行,或者还有未执行的动画,则调用scheduleAnimation方法

if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {

scheduleAnimation();

}

}

这里代码量有点多,我们先分析在遍历mPendingAnimations和mDelayedAnims队列时,都调用到ValueAnimator的startAnimation(AnimationHandler handler)方法,下面我们一起来分析

3.4.15 ValueAnimator.startAnimation方法

// ValueAnimator

private void startAnimation(AnimationHandler handler) {

if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {

Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),

System.identityHashCode(this));

}

// 注意到没有,这里又调用到了ObjectAnimator的initAnimation方法

initAnimation();

// 把当前正在执行的动画加入到AnimationHandler的mAnimations队列中

handler.mAnimations.add(this);

if (mStartDelay > 0 && mListeners != null) {

// Listeners were already notified in start() if startDelay is 0; this is

// just for delayed animations

notifyStartListeners();

}

}

在上面的代码中,大家注意到了没有,在startAnimation方法中调用到了ObjectAnimator的initAnimation()方法,这个initAnimation方法在上面已经分析了,回过头来看一下,这个initAnimation方法就是初始化动画执行过程用到的参数值,如关键帧Keyframe、get和set方法。那么在上面ObjectAnimator.start()方法中已经初始化了,为什么这里还要调用呢,这是为了使设置了mStartDelay延迟时间的Animator进行初始化调用的。

回到AnimatationHandlers的doAnimationFrame(long frameTime)方法中,在遍历mTmpAnimations队列时,调用了ValueAnimator的doAnimationFrame(long frameTime),接下来我们一起来看一下是怎么实现的

3.4.16 探究ValueAnimator.doAnimationFrame()方法

// ValueAnimator

final boolean doAnimationFrame(long frameTime) {

// mPlayingState状态改变

if (mPlayingState == STOPPED) {

mPlayingState = RUNNING;

if (mSeekFraction < 0) {

mStartTime = frameTime;

} else {

long seekTime = (long) (mDuration * mSeekFraction);

mStartTime = frameTime - seekTime;

mSeekFraction = -1;

}

mStartTimeCommitted = false; // allow start time to be compensated for jank

}

if (mPaused) {

if (mPauseTime < 0) {

mPauseTime = frameTime;

}

return false;

} else if (mResumed) {

mResumed = false;

if (mPauseTime > 0) {

// Offset by the duration that the animation was paused

mStartTime += (frameTime - mPauseTime);

mStartTimeCommitted = false; // allow start time to be compensated for jank

}

}

// The frame time might be before the start time during the first frame of

// an animation. The "current time" must always be on or after the start

// time to avoid animating frames at negative time intervals. In practice, this

// is very rare and only happens when seeking backwards.

final long currentTime = Math.max(frameTime, mStartTime);

return animationFrame(currentTime);

}

在最后一行中调用到了ValueAnimator.animationFrame()方法

// ValueAnimator

boolean animationFrame(long currentTime) {

boolean done = false;

switch (mPlayingState) {

case RUNNING:

case SEEKED:

// 计算fraction

float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;

// 在上面的例子中,mDuration设置为5000ms

if (mDuration == 0 && mRepeatCount != INFINITE) {

// Skip to the end

mCurrentIteration = mRepeatCount;

if (!mReversing) {

mPlayingBackwards = false;

}

}

// 这里处理循环动画的情况,我们暂时可以略过

if (fraction >= 1f) {

if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {

// Time to repeat

if (mListeners != null) {

int numListeners = mListeners.size();

for (int i = 0; i < numListeners; ++i) {

mListeners.get(i).onAnimationRepeat(this);

}

}

if (mRepeatMode == REVERSE) {

mPlayingBackwards = !mPlayingBackwards;

}

mCurrentIteration += (int) fraction;

fraction = fraction % 1f;

mStartTime += mDuration;

// Note: We do not need to update the value of mStartTimeCommitted here

// since we just added a duration offset.

} else {

done = true;

fraction = Math.min(fraction, 1.0f);

}

}

// 根据上面的例子,mPlayingBackwards为false

if (mPlayingBackwards) {

fraction = 1f - fraction;

}

// 注意啦,这里调用到ObjectAnimator的animateValue方法

animateValue(fraction);

break;

}

return done;

}

通过上面的分析,我们注意到,在animationFrame(long currentTime)方法中调用了ObjectAnimator的animateValue(float fraction),而这个方法我们在上面已经分析过了,终于又回来了,这个animateValue方法主要就是根据fraction计算属性值,然后通过反射的方式修改目标mTarget的alpha属性值,从而达到mTarget的alpha值从0.0到1.0的渐显效果。

终于到了见证奇迹的地方,ObjectAnimator动画执行就是不断的通过mChoreographer的postCallback方法实现在帧渲染时执行mAnimate这个Runnable,在animateValue方法中利用反射方式改变目标target的属性值,从而实现动画效果的。

至此,ObjectAnimator动画执行的过程已经全部完毕。

4.结尾

最后我们回到博客开头我提到的想法,就是如果在ObjectAnimator动画结束回调函数onAnimationEnd中重新start此动画,是否能达到循环播放动画呢?我们仔细分析ValueAnimator的endAnimation(AnimationHandler handler)方法

// ValueAnimator

protected void endAnimation(AnimationHandler handler) {

// 清空AnimationHandler用到的队列

handler.mAnimations.remove(this);

handler.mPendingAnimations.remove(this);

handler.mDelayedAnims.remove(this);

mPlayingState = STOPPED;

mPaused = false;

if ((mStarted || mRunning) && mListeners != null) {

if (!mRunning) {

// If it's not yet running, then start listeners weren't called. Call them now.

notifyStartListeners();

}

ArrayList tmpListeners =

(ArrayList) mListeners.clone();

int numListeners = tmpListeners.size();

for (int i = 0; i < numListeners; ++i) {

// 回调AnimatorListener.onAnimationEnd,在我的想法中就是在这里重新start动画

tmpListeners.get(i).onAnimationEnd(this);

}

}

// 这些标志位都置为false

mRunning = false;

mStarted = false;

mStartListenersCalled = false;

mPlayingBackwards = false;

mReversing = false;

mCurrentIteration = 0;

if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {

Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),

System.identityHashCode(this));

}

}

通过分析,原来在AnimatorListener.onAnimationEnd回调中即使重新start动画,由于当时mStartListenersCalled为true,所以再次start动画时不会在回调AnimatorListener.onAnimationStart方法,在后面又把mRunning和mStarted两个标志位改为false,导致在第二次start的动画结束时调用endAnimation方法中因为这两个标志位都是为false,所以不会再次回调AnimatorListener.onAnimationEnd方法,也就是说重新start起来的动画执行完毕就不会再此触发start动作,所以验证博客开头代码的实验效果。

这篇博客已经完毕,非常感谢您对本篇的关注,希望能对您了解ObjectAnimator属性动画的实现有帮助,要是有不足之处欢迎指正,我们相互讨论学习!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值