Android Animator 源碼分析
下面分析下Animator在Framework層的實現
從ObjectAnimator.ofFloat()開始
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
這個工廠方法會創建一個ObjectAnimator對象,在創建時同時設置屬性動畫的目標和屬性名
private ObjectAnimator(Object target, String propertyName) {
setTarget(target);
setPropertyName(propertyName);
}
// 設置目標對象
@Override
public void setTarget(@Nullable Object target) {
final Object oldTarget = getTarget();
if (oldTarget != target) {
if (isStarted()) {
cancel();
}
// target必須是一個弱引用對象
mTarget = target == null ? null : new WeakReference<Object>(target);
// New target should cause re-initialization prior to starting
mInitialized = false; // 記錄尚未初始化,ValueAnimator的標志位,一會要用
}
}
// 設置屬性名稱
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進行
// Animator只進行數值計算
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;
}
ofFloat還有一步就是調用這個方法
@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
// 這是mProperty是為null的
if (mProperty != null) {
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
}
} else {
super.setFloatValues(values);
}
}
setValues這個過程有點長,按照順序先寫下吧
// PropertyValueHolder中
// 獲取PropertyValuesHolder
public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
// 創建子類
return new FloatPropertyValuesHolder(propertyName, values);
}
public FloatPropertyValuesHolder(String propertyName, float... values) {
super(propertyName);
setFloatValues(values);
}
@Override
public void setFloatValues(float... values) {
// 這個過程會取得value的類型
super.setFloatValues(values);
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}
// super.setFloatValues()
// 取得Value的類型
public void setFloatValues(float... values) {
mValueType = float.class;
mKeyframes = KeyframeSet.ofFloat(values);
}
然后設置KeyFrame了,KeyFrame時屬性動畫中的關鍵幀,通過設置關鍵幀來保證動畫執行時序性
// ~KeyFrameSet中
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);
}
接下來看關鍵幀怎么創建的
//keyFrame中
public static Keyframe ofFloat(float fraction) {
return new FloatKeyframe(fraction);
}
// FloatKeyFrame中
FloatKeyframe(float fraction) {
mFraction = fraction;
mValueType = float.class;
}
仔細看了看,發現KeyFrame其實只是對當前的value和fraction進行一個記錄,不同類型的KeyFrame會設置不同的mValueType
KeyFrame中的屬性值,一會回來再看
/**
* Flag to indicate whether this keyframe has a valid value. This flag is used when an
* animation first starts, to populate placeholder keyframes with real values derived
* from the target object.
*/
boolean mHasValue;
/**
* Flag to indicate whether the value in the keyframe was read from the target object or not.
* If so, its value will be recalculated if target changes.
*/
boolean mValueWasSetOnStart;
/**
* The time at which mValue will hold true.
*/
float mFraction;
/**
* The type of the value in this Keyframe. This type is determined at construction time,
* based on the type of the <code>value</code> object passed into the constructor.
*/
Class mValueType;
/**
* The optional time interpolator for the interval preceding this keyframe. A null interpolator
* (the default) results in linear interpolation over the interval.
*/
private TimeInterpolator mInterpolator = null;
回來看哪個keyframe的ofFloat方法,最終會創建一個關鍵幀集合
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過程就結束了,下面看下其他方法
setDuration()
設置動畫的執行時間
這個就是將執行時間寫入屬性中,一會會用到
@Override
public ValueAnimator setDuration(long duration) {
if (duration < 0) {
throw new IllegalArgumentException("Animators cannot have negative duration: " +
duration);
}
mDuration = duration;
return this;
}
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 {
mInterpolator = new LinearInterpolator();
}
}
setEvaluator()
設置估值器
估值器實際上是在KeyFrame中使用的
public void setEvaluator(TypeEvaluator value) {
if (value != null && mValues != null && mValues.length > 0) {
mValues[0].setEvaluator(value);
}
}
public void setEvaluator(TypeEvaluator evaluator) {
mEvaluator = evaluator;
mKeyframes.setEvaluator(evaluator);
}
//KeyFrameSet中
public void setEvaluator(TypeEvaluator evaluator) {
// 使用屬性值進行保存
mEvaluator = evaluator;
}
start()
開始分析開始動畫的方法
從ObjectAnimator開始,會調用到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;
// Special case: reversing from seek-to-0 should act as if not seeked at all.
// mSeekFraction這個標志位,第一次啟動動畫時是-1,暫時不會進入
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;
// 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;
// 這里從線程中取出AnimatonHandler,一會分析
AnimationHandler animationHandler = AnimationHandler.getInstance();
animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
// mStartedDelay指示這個動畫是否已經從startDelay中開始執行。
// 這里mStartDelay=0可以順利啟動
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.
// 第一次啟動,設置當前啟動時間為0
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
AnimationHandler分析
AnimationHandler 是一個實現了Runnable接口的ValueAnimator內部類
從當前線程中取得AnimationHandler對象
public static AnimationHandler getInstance() {
if (sAnimatorHandler.get() == null) {
sAnimatorHandler.set(new AnimationHandler());
}
return sAnimatorHandler.get();
}
然后注冊了兩個回調,看下具體方法
/**
* Register to get a callback on the next frame after the delay.
*/
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
interface AnimationFrameCallback {
/**
* Run animation based on the frame time.
* @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time
* base.
*/
// 每一幀動畫開始時回調
void doAnimationFrame(long frameTime);
/**
* This notifies the callback of frame commit time. Frame commit time is the time after
* traversals happen, as opposed to the normal animation frame time that is before
* traversals. This is used to compensate expensive traversals that happen as the
* animation starts. When traversals take a long time to complete, the rendering of the
* initial frame will be delayed (by a long time). But since the startTime of the
* animation is set before the traversal, by the time of next frame, a lot of time would
* have passed since startTime was set, the animation will consequently skip a few frames
* to respect the new frameTime. By having the commit time, we can adjust the start time to
* when the first frame was drawn (after any expensive traversals) so that no frames
* will be skipped.
*
* @param frameTime The frame time after traversals happen, if any, in the
* {@link SystemClock#uptimeMillis()} time base.
*/
// 每一幀開始遍歷時回調
void commitAnimationFrame(long frameTime);
}
從ValueAnimator中看下具體實現
// 這里對每一幀進行處理,如果時從暫停恢復,將調整開始時間
public final void doAnimationFrame(long frameTime) {
AnimationHandler handler = AnimationHandler.getInstance();
if (mLastFrameTime == 0) {
// First frame
handler.addOneShotCommitCallback(this);
if (mStartDelay > 0) {
startAnimation();
}
if (mSeekFraction < 0) {
mStartTime = frameTime;
} else {
long seekTime = (long) (getScaledDuration() * mSeekFraction);
mStartTime = frameTime - seekTime;
mSeekFraction = -1;
}
mStartTimeCommitted = false; // allow start time to be compensated for jank
}
mLastFrameTime = frameTime;
if (mPaused) {
mPauseTime = frameTime;
handler.removeCallback(this);
return;
} 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
}
handler.addOneShotCommitCallback(this);
}
// 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);
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
endAnimation();
}
}
這個回調也是遍歷時調整啟動時間的
public void commitAnimationFrame(long frameTime) {
if (!mStartTimeCommitted) {
mStartTimeCommitted = true;
long adjustment = frameTime - mLastFrameTime;
if (adjustment > 0) {
mStartTime += adjustment;
if (DEBUG) {
Log.d(TAG, "Adjusted start time by " + adjustment + " ms: " + toString());
}
}
}
}
startAnimation()
這段代碼時start()中真正啟動動畫的代碼, 必須在UI線程 ,仔細研究下
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();
}
}
先會調用ObjectAnimator的initAnimation,只要是初始化反射的方法,對Target的屬性值進行修改
@CallSuper
@Override
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();
}
}
PropertyValuesHolder的setupSetterAndGetter()
初始化反射修改器,這里代碼有點多
void setupSetterAndGetter(Object target) {
mKeyframes.invalidateCache();
if (mProperty != null) {
// check to make sure that mProperty is on the class of target
// try-catch判斷是否這個屬性在這個類里
try {
Object testValue = null;
List<Keyframe> 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;
}
}
// 如果還沒有找到屬性的話,判斷get和set方法是否存在
// We can't just say 'else' here because the catch statement sets mProperty to null.
if (mProperty == null) {
Class targetClass = target.getClass();
if (mSetter == null) {
// 初始化setter
setupSetter(targetClass);
}
List<Keyframe> 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) {
// 初始化getter
setupGetter(targetClass);
if (mGetter == null) {
// Already logged the error - just return to avoid NPE
return;
}
}
try {
Object value = convertBack(mGetter.invoke(target));
kf.setValue(value);
kf.setValueWasSetOnStart(true);
} catch (InvocationTargetException e) {
Log.e("PropertyValuesHolder", e.toString());
} catch (IllegalAccessException e) {
Log.e("PropertyValuesHolder", e.toString());
}
}
}
}
}
繼續尋找set和get方法
private Method setupSetterOrGetter(Class targetClass,
HashMap<Class, HashMap<String, Method>> 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
HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
boolean wasInMap = false;
if (propertyMap != null) {
wasInMap = propertyMap.containsKey(mPropertyName);
if (wasInMap) {
setterOrGetter = propertyMap.get(mPropertyName);
}
}
if (!wasInMap) {
// 通過屬性值尋找方法
setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
if (propertyMap == null) {
propertyMap = new HashMap<String, Method>();
propertyMapMap.put(targetClass, propertyMap);
}
// 放入map中
propertyMap.put(mPropertyName, setterOrGetter);
}
}
//返回給mSetter或mGetter
return setterOrGetter;
}
然后調用ValueAnimator的initAnimation
這里會初始化每一個PropertyValuesHolder
void initAnimation() {
if (!mInitialized) {
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
// 這里會初始化每一個PropertyValuesHolder
mValues[i].init();
}
mInitialized = true;
}
}
PropertyValuesHolder中的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
// 給每一個KeyFrame設置估值器,前面講過
mKeyframes.setEvaluator(mEvaluator);
}
}
start()中的setCurrentPlayTime()
start()中調用的啟動動畫方法
public void setCurrentPlayTime(long playTime) {
// 計算fraction
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
// 將計算出來的Fraction設置給動畫
public void setCurrentFraction(float fraction) {
initAnimation();
fraction = clampFraction(fraction);
long seekTime = (long) (getScaledDuration() * fraction);
// 當前執行動畫的時間
long currentTime = AnimationUtils.currentAnimationTimeMillis();
mStartTime = currentTime - seekTime;
mStartTimeCommitted = true; // do not allow start time to be compensated for jank
if (!isPulsingInternal()) {
// If the animation loop hasn't started, the startTime will be adjusted in the first
// frame based on seek fraction.
mSeekFraction = fraction;
}
mOverallFraction = fraction;
final float currentIterationFraction = getCurrentIterationFraction(fraction);
// 拿到Fraction以后,開始變化數值
animateValue(currentIterationFraction);
}
對動畫數值進行運算
先會調用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.
cancel();
return;
}
// 這里調用ValueAnimator中的animateValue計算數值
// ValueAnimator與屬性值無關的,一會再看
super.animateValue(fraction);
int numValues = mValues.length;
//反射修改每個方法值
//這里修改完這一輪動畫就結束了
for (int i = 0; i < numValues; ++i) {
mValues[i].setAnimatedValue(target);
}
}
ValueAnimator中的animateValue進行插值運算
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);
}
// 回調update監聽器
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
PropertyValuesHolder中的calculateValue()
通過獲取的fraction,對每個屬性值進行變化,這個過程通過反射進行
void calculateValue(float fraction) {
// 從KeyFrame中獲取計算完成的屬性值,我們來看下這個方法
Object value = mKeyframes.getValue(fraction);
// 這里取到屬性值
mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}
KeyFrameSet中的getValue()
//KeyFrameSet中
public Object getValue(float fraction) {
// Special-case optimization for the common case of only two keyframes
// 只有兩個關鍵幀的情況
if (mNumKeyframes == 2) {
if (mInterpolator != null) {
fraction = mInterpolator.getInterpolation(fraction);
}
// 通過估值器進行取值
return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
mLastKeyframe.getValue());
}
// 此處處理多個關鍵幀的情況,取出倆個關鍵幀之前的Fraction
// 進行計算
if (fraction <= 0f) {
final Keyframe nextKeyframe = mKeyframes.get(1);
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
final float prevFraction = mFirstKeyframe.getFraction();
float intervalFraction = (fraction - prevFraction) /
(nextKeyframe.getFraction() - prevFraction);
return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
nextKeyframe.getValue());
} else if (fraction >= 1f) {
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
if (interpolator != null) {
fraction = interpolator.getInterpolation(fraction);
}
final float prevFraction = prevKeyframe.getFraction();
float intervalFraction = (fraction - prevFraction) /
(mLastKeyframe.getFraction() - prevFraction);
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
mLastKeyframe.getValue());
}
Keyframe prevKeyframe = mFirstKeyframe;
// 對兩個關鍵幀之前的fraction使用估值器進行計算
for (int i = 1; i < mNumKeyframes; ++i) {
Keyframe nextKeyframe = mKeyframes.get(i);
if (fraction < nextKeyframe.getFraction()) {
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
final float prevFraction = prevKeyframe.getFraction();
float intervalFraction = (fraction - prevFraction) /
(nextKeyframe.getFraction() - prevFraction);
// Apply interpolator on the proportional duration.
if (interpolator != null) {
intervalFraction = interpolator.getInterpolation(intervalFraction);
}
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
nextKeyframe.getValue());
}
prevKeyframe = nextKeyframe;
}
// shouldn't reach here
return mLastKeyframe.getValue();
}
PropertyValueHolder中的setAnimatedValue()反射修改屬性值
如果是ofFloat創建的FloatPropertyValueHolder,那么該方法為
@Override
void setAnimatedValue(Object target) {
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());
}
}
}
動畫流程就是這樣
來自:http://blog.csdn.net/y874961524/article/details/53984282