这篇文章主要讲解一些属性动画的源码,通过此篇文章能够帮助我们更好的理解和使用属性动画。
1、基本使用
我们先看下属性的动画的基本使用,并依此为入口,逐步分析属性动画的源码:
ObjectAnimator
.ofInt(target,propName,values[])
.setInterpolator(LinearInterpolator)
.setEvaluator(IntEvaluator)
.setDuration(500)
.start();
上面就是属性动画的基本使用,先通过ObjectAnimator的静态方法ofInt新建ObjectAnimator对象,并传入构造参数,target:要操作的View,propName:要操作的View的属性,values[]:动画在执行期间将要使用的一系列值,构造完对象之后,通过setEvaluator设置插值器,设置执行时间,最后start执行,那么我们就先从构造方法开始一步一步分析
2、源码分析
1、ofInt
我们首先看下ofInt的代码:
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setIntValues(values);
return anim;
}
new了一个ObjectAnimator对象,并传入target和propertyName,来看看构造方法
private ObjectAnimator(Object target, String propertyName) {
setTarget(target);
setPropertyName(propertyName);
}
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;
}
}
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.
if (mValues != null) {
PropertyValuesHolder valuesHolder = mValues[0];
String oldName = valuesHolder.getPropertyName();
valuesHolder.setPropertyName(propertyName);
mValuesMap.remove(oldName);
mValuesMap.put(propertyName, valuesHolder);
}
mPropertyName = propertyName;
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
其实就是记录下target和propertyName;
构建完构造方法之后,调用了setIntValues;
@Override
public void setIntValues(int... 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.ofInt(mProperty, values));
} else {
setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
}
} else {
super.setIntValues(values);
}
}
调用setValues,并传入PropertyValuesHolder.ofInt(mPropertyName, values)参数,其实就是将values封装成PropertyValuesHolder,我们来看看PropertyValuesHolder.ofInt方法
public static PropertyValuesHolder ofInt(String propertyName, int... values) {
return new IntPropertyValuesHolder(propertyName, values);
}
实例化了一个IntPropertyValuesHolder对象
public IntPropertyValuesHolder(String propertyName, int... values) {
super(propertyName);
setIntValues(values);
}
private PropertyValuesHolder(String propertyName) {
mPropertyName = propertyName;
}
在IntPropertyValuesHolder构造方法中,保存propertyName,并调用setIntValues方法,来看看这个方法:
@Override
public void setIntValues(int... values) {
super.setIntValues(values);
mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
}
调用了父类的setIntValues方法,并将mIntKeyframes赋值,我们继续看看super.setIntValues方法
public void setIntValues(int... values) {
mValueType = int.class;
mKeyframes = KeyframeSet.ofInt(values);
}
调用了KeyframeSet.ofInt方法,
public static KeyframeSet ofInt(int... values) {
int numKeyframes = values.length;
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
if (numKeyframes == 1) {
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
} else {
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
for (int i = 1; i < numKeyframes; ++i) {
keyframes[i] =
(IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
}
}
return new IntKeyframeSet(keyframes);
}
这个就是比较关键的部分了,先获取values的长度,并实例化一个keyframes数组,最小长度是2,如果传入的values的长度等于1,则将keyframes的第一个数设置为0,第二个数设置为传入的values值,否则,就遍历传入的值,将values里面的值,均匀的赋值给keyframes,最后返回intKeyFrameSet。
至此,ofInt的源码已经分析完了,我们稍微总结一下,ObjectAnimator将传入的target和propertyName保存起来,然后通过propertyName和values构建PropertyValuesHolders,进一步的将values中的数值按照关键帧的形式存储在PropertyValuesHolder中的KeyFrameSet中,这一部分主要是做存储操作
2、setInterpolator
setInterpolator其实调用的是父类ValueAnimator的方法,
@Override
public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
}
仅仅是记录下插值器
3、setEvaluator
public void setEvaluator(TypeEvaluator value) {
if (value != null && mValues != null && mValues.length > 0) {
mValues[0].setEvaluator(value);
}
}
设置了mValues的估值算法,也就是调用了PropertyValuesHolder的setEvaluator
public void setEvaluator(TypeEvaluator evaluator) {
mEvaluator = evaluator;
mKeyframes.setEvaluator(evaluator);
}
设置给了PropertyValuesHolder和KeyframeSet
4、setDuration
@NonNull
public ObjectAnimator setDuration(long duration) {
super.setDuration(duration);
return this;
}
@Override
public ValueAnimator setDuration(long duration) {
if (duration < 0) {
throw new IllegalArgumentException("Animators cannot have negative duration: " +
duration);
}
mUnscaledDuration = duration;
updateScaledDuration();
return this;
}
仅仅是保存了一下动画的执行时间,也没什么好说的
5、start
@Override
public void start() {
// See if any of the current active/pending animators need to be canceled
AnimationHandler handler = sAnimationHandler.get();
if (handler != null) {
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();
}
}
}
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();
}
}
}
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));
}
}
super.start();
}
先是从本线程中取出AnimationHandler,然后做一些cancel操作,最后调用super.start,AnimationHandler是ValueAnimation的内部类(不用的api可能不太一样,当前api版本是23)
再来看看ValueAnimator的start方法
@Override
public void start() {
start(false);
}
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
//当前动画是否是reverse;
mReversing = playBackwards;
mPlayingBackwards = playBackwards;
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;
}
//mCurrentIteration 记录当前的动画的执行次数(与setRepeatCount有关)
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;
//stop状态
mPlayingState = STOPPED;
mStarted = true;
mStartedDelay = false;
mPaused = false;
updateScaledDuration(); // in case the scale factor has changed since creation time
//从当前线程获取AnimationHandler
AnimationHandler animationHandler = getOrCreateAnimationHandler();
//将此Animator添加到animationHandler的mPendingAnimations,这个变量是ArrayList<ValueAnimator>类型的
animationHandler.mPendingAnimations.add(this);
//如果没有延迟
if (mStartDelay == 0) {
// This sets the initial value of the animation, prior to actually starting it running
if (prevPlayingState != SEEKED) {
//执行这个方法,下面去分析
setCurrentPlayTime(0);
}
//设置状态
mPlayingState = STOPPED;
mRunning = true;
//如果设置了AnimatorListener则会回调onAnimationStart方法
notifyStartListeners();
}
//调用animation.start方法, 一会分析
animationHandler.start();
}
最终调用了start(false)方法,这段代码有点长,其实就是设置一些状态,将这个Animator放到AnimationHandler的执行队列中,回调onAnimationStart方法
我们来看看setCurrentPlayTime(0):
public void setCurrentPlayTime(long playTime) {
float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1;
setCurrentFraction(fraction);
}
通过playTime计算出fraction,然后作为参数传递给setCurrnetFraction
public void setCurrentFraction(float fraction) {
//调用initAnimation,其实就是调用遍历values,给每个值调用PropertyValuesHolder的init方法,来设置mEvaluator估值器
initAnimation();
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;
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);
}
最后调用animateValue方法
void animateValue(float fraction) {
final Object target = getTarget();
if (mTarget != null && target == null) {
// We lost the target reference, cancel and clean up.
cancel();
return;
}
调用父类animateValue
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//为target设置属性值
mValues[i].setAnimatedValue(target);
}
}
super.animateValue:
void animateValue(float fraction) {
//使用我们设置的插值器mInterpolator通过fraction来转化成动画完成度
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//然后在将fraction交给估值算法mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();进行计算得到当前时间点,属性应该的值;最后会反射对我们设置的属性进行设置。
mValues[i].calculateValue(fraction);
}
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
//回调onAnimationUpdate
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
在其内部,调用了mKeyframeSet的getValue,这里注意我们的IntKeyFrameSet,千万不要看错方法了。
@Override
public Object getValue(float fraction) {
return getIntValue(fraction);
}
@Override
public int getIntValue(float fraction) {
if (mNumKeyframes == 2) {
if (firstTime) {
firstTime = false;
firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
deltaValue = lastValue - firstValue;
}
if (mInterpolator != null) {
fraction = mInterpolator.getInterpolation(fraction);
}
if (mEvaluator == null) {
return firstValue + (int)(fraction * deltaValue);
} else {
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
}
}
//省略代码。。
}
在其内部,因为我们只设置了一个目标属性值,所以只有两个关键帧;
setCurrentPlayTime已经设置完了,下面我们回到初始地方来看看animationHandler.start方法
public void start() {
scheduleAnimation();
}
private void scheduleAnimation() {
if (!mAnimationScheduled) {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
mAnimationScheduled = true;
}
}
start方法调用了scheduleAnimation方法,最终Choreographer调用postCallback,我们来啊看你mAnimate:
final Runnable mAnimate = new Runnable() {
@Override
public void run() {
mAnimationScheduled = false;
doAnimationFrame(mChoreographer.getFrameTime());
}
};
最终Choreographer肯定会回调这个run方法,继续来看doAnimationFrame:
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.
while (mPendingAnimations.size() > 0) {
ArrayList<ValueAnimator> pendingCopy =
(ArrayList<ValueAnimator>) mPendingAnimations.clone();
mPendingAnimations.clear();
int count = pendingCopy.size();
for (int i = 0; i < count; ++i) {
ValueAnimator anim = pendingCopy.get(i);
// If the animation has a startDelay, place it on the delayed list
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();
for (int i = 0; i < numDelayedAnims; ++i) {
ValueAnimator anim = mDelayedAnims.get(i);
if (anim.delayedAnimationFrame(frameTime)) {
mReadyAnims.add(anim);
}
}
int numReadyAnims = mReadyAnims.size();
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.clear();
}
// Now process all active animations. The return value from animationFrame()
// tells the handler whether it should now be ended
int numAnims = mAnimations.size();
for (int i = 0; i < numAnims; ++i) {
mTmpAnimations.add(mAnimations.get(i));
}
for (int i = 0; i < numAnims; ++i) {
ValueAnimator anim = mTmpAnimations.get(i);
if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
mEndingAnims.add(anim);
}
}
mTmpAnimations.clear();
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.
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.
if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
scheduleAnimation();
}
}
while循环,遍历所有的mPendingAnimations中的ObjectAnimator,依此调用anim.startAnimation();
在anim.startAnimation内部其实就是调用了handler.mAnimations.add();将当前动画加入到animationHandler的mAnimations集合中
然后将animationHandler的anim,加入到mTmpAnimations中,然后依此调用anim.doAnimationFrame方法,如果返回true,则将该动画加入到结束动画结合中。
循环调用mEndingAnims,mEndingAnims.get(i).endAnimation(this);内部,会将动画移除mAnimations,回调动画监听接口onAnimationEnd;以及重置各种标志变量。
如果mAnimations不为null,则再次调用scheduleAnimation();
3、总结
ofInt中实例化了一个ObjectAnimator对象,然后设置了target,propName,values(PropertyValuesHolder) ;然后分别在setInterpolator,setDuration设置了Interpolator
和duration。其中setEvaluator是给PropertyValuesHolder,以及keyframeSet设置估值算法。
PropertyValueHolder实际上是IntPropertyValueHolder类型对象,包含propName,valueType,keyframeSet .
keyframeset中存了Keyframe集合,keyframe中存储了(fraction , valuetype , value , hasValue)。
在start()中:
首先,步骤1:更新动画各种状态,然后初步计算fraction为(currentTime - mStartTime) / mDuration;然后将这个fraction交给我们的插值器计算后得到新的fraction,再将新的fraction交给我们的估值算法,估值算法根据开始、结束、fraction得到当前属性(动画作用的属性)应该的值,最大调用反射进行设置;
当然了:start中还会根据动画的状态,如果没有结束,不断的调用scheduleAnimation();该方法内部利用mChoreographer不断的去重复我们的上述步骤1。