关于Android 属性动画的使用,请见
blog.csdn.net/y874961524/…
下面分析下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());
}
}
}
动画流程就是这样