切入点
ObjectAnimator anim = ObjectAnimator.ofFloat(TextView(this), "scaleX", 0f, 1f)
anim.start()
从使用方式来分析, 属性动画有两个值得关注的点
- ObjectAnimator.ofFloat
- anim.start()
接下来一一分析
ObjectAnimator.ofFloat
/**
* objectAnimator.ofFloat
*/
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
// 1. 构建了 ObjectAnimator 实例对象
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
// 2. 设置我们传入的数值
anim.setFloatValues(values);
return anim;
}
/**
* ObjectAnimator.Constructor
*/
private ObjectAnimator(Object target, String propertyName) {
setTarget(target);// 给 mTarget(View) 赋值
setPropertyName(propertyName);// 给 mPropertyName(String) 赋值
}
/**
* ObjectAnimator.setFloatValues
*/
public void setFloatValues(float... values) {
if (mValues == null || mValues.length == 0) {
if (mProperty != null) {
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {
// 2.1 通过 PropertyValuesHolder.ofFloat(...) 获取 PropertyValuesHolder 对象
// 2.2 调用 setValues 方法
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
}
} else {
super.setFloatValues(values);
}
}
/**
* ValueAnimator.setFloatValues
*/
public void setValues(PropertyValuesHolder... values) {
int numValues = values.length;
mValues = values;// 给成员变量赋值
// 写入 mValuesMap 集合中
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
PropertyValuesHolder valuesHolder = values[i];
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
好了分析了上面的源码, 我们可以看到 ObjectAnimator.ofFloat 主要做了如下
- 给成员变量 mTarget, mPropertyName 赋值
- 通过 PropertyValuesHolder.ofFloat 构建 PropertyValuesHolder 对象
- 将 PropertyValuesHolder 写入缓存 mValuesMap 中, 给 mValues, mValueMap 赋值
好, 接下来, 看看这个 PropertyValuesHolder.ofFloat 到底做了什么
/**
* PropertyValuesHolder.ofFloat
*/
public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
return new FloatPropertyValuesHolder(propertyName, values);
}
/**
* PropertyValuesHolder.Constructor
*/
public FloatPropertyValuesHolder(String propertyName, float... values) {
super(propertyName);
setFloatValues(values);
}
/**
* PropertyValuesHolder.setFloatValues
*/
public void setFloatValues(float... values) {
super.setFloatValues(values);
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}
/**
* PropertyValuesHolder.setFloatValues
*/
public void setFloatValues(float... values) {
mValueType = float.class;
// 重点来了, 给成员变量 mKeyframes 赋值
mKeyframes = KeyframeSet.ofFloat(values);
}
/**
* KeyframeSet.ofFloat
*/
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
int numKeyframes = values.length;
// 将我们传入的 values 构建 Keyframe 的数组
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
// 若我们只传入一个值, 则 keyframes 给我们补上起始值 0f
if (numKeyframes == 1) {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
} 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]);
}
}
// 通过我们的 keyframes 关键帧数组 来构建 FloatKeyframeSet 对象
return new FloatKeyframeSet(keyframes);
}
通过 PropertyValuesHolder.ofFloat 分析可知
- PropertyValuesHolder 中有一个 mKeyframes(KeyframeSet) 成员变量
- mKeyframes(KeyframeSet) 中又保存了 FloatKeyframe[] 数组
- FloatKeyframe 中保存动画执行百分比 fraction 时对应 value 的值
好了, 至此 ObjectAnimator.ofFloat 做的事情就比较清楚了, 接下来看看 ObjectAnimator.start 方法是如何操作存储的这些数值的
ObjectAnimator.start
/**
* ObjectAnimator.start
*/
public void start() {
AnimationHandler.getInstance().autoCancelBasedOn(this);
// 直接调用了父类的 start
super.start();
}
/**
* ValueAnimator.start
*/
public void start() {
start(false);
}
/**
* ValueAnimator.start
*/
private void start(boolean playBackwards) {
// ...忽略相关代码
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 = -1;
mFirstFrameTime = -1;
mStartTime = -1;
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
// 1. 关注这个方法
startAnimation();
if (mSeekFraction == -1) {
// 2. 立即执行
setCurrentPlayTime(0);
} else {
// 延迟执行
setCurrentFraction(mSeekFraction);
}
}
}
可见 ObjectAnimator.start 最终会调用到 ValueAnimator 中的 start 方法, 我们先分析 startAnimation
/**
* ValueAnimator.startAnimation
*/
private void startAnimation() {
mAnimationEndRequested = false;
// (重点) 初始化动画, 这个方法被 ObjectAnimator 复写了
initAnimation();
// 更改标记位置
mRunning = true;
if (mSeekFraction >= 0) {
mOverallFraction = mSeekFraction;
} else {
mOverallFraction = 0f;
}
// 回调接口中的 onStart 方法
if (mListeners != null) {
notifyStartListeners();
}
}
/**
* ObjectAnimator.startAnimation
*/
void initAnimation() {
if (!mInitialized) {
final Object target = getTarget();
if (target != null) {
final int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
// 1. 遍历 PropertyValuesHolder 数组, 分别调用 PropertyValuesHolder.setupSetterAndGetter
mValues[i].setupSetterAndGetter(target);
}
}
// 2. 回调父类的 initAnimation
super.initAnimation();
}
}
/**
* PropertyValuesHolder.setupSetterAndGetter
*/
void setupSetterAndGetter(Object target) {
...
if (mProperty == null) {
Class targetClass = target.getClass();
// 这里看到了一个新的属性为 mSetter: Method
// 很明显了, mSetter 的作用是通过反射去调用 target 的目标方法
// 例: mImageView.setScaleX(0f), setTranslationX() 等;
if (mSetter == null) {
// 1.1 拼接相关的 set 方法
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) {
// 1.2 拼接相关的 get 方法
setupGetter(targetClass);
...
}
}
}
}
}
/**
* ValueAnimator.initAnimation
*/
void initAnimation() {
if (!mInitialized) {
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].init();
}
mInitialized = true;
}
}
/**
* ValueAnimator.init
*/
void init() {
// 配置估值器相关
if (mEvaluator == null) {
mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
(mValueType == Float.class) ? sFloatEvaluator :
null;
}
if (mEvaluator != null) {
mKeyframes.setEvaluator(mEvaluator);
}
}
可以看到 startAnimation() 这个方法主要做了一些初始化工作
- 根据 target 去拼接相关的 GetOrSet Method 方法, 用于后续反射调用更新 View 的属性值
- 配置了估值器相关
- 回调接口中的 onStart 方法
至此我们还是没有看到, 属性动画执行的过程, 但看到了 View 相关方法的拼接, 让我们感觉距离最后的执行又近了一步, 继续分析 setCurrentPlayTime(0)
/**
* ValueAnimator.init
*/
public void setCurrentPlayTime(long playTime) {
float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
setCurrentFraction(fraction);
}
/**
* ValueAnimator.init
*/
public void setCurrentFraction(float fraction) {
...
final float currentIterationFraction = getCurrentIterationFraction(fraction); // 获取动画执行的百分比
// 接下来看看 animateValue(被子类复写) 对这个动画百分比做了什么处理
animateValue(currentIterationFraction);
}
/**
* ObjectAnimator.init
*/
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;
// 遍历数组调用了 PropertyValuesHolder.setAnimatedValue 方法
for (int i = 0; i < numValues; ++i) {
mValues[i].setAnimatedValue(target);
}
}
/**
* PropertyValuesHolder.setAnimatedValue
*/
void setAnimatedValue(Object target) {
if (mProperty != null) {
mProperty.set(target, getAnimatedValue());
}
if (mSetter != null) {
try {
// 终于!!! 看到了反射调用方法, 最终实现了 View 的动态改变
mTmpValueArray[0] = getAnimatedValue();
mSetter.invoke(target, mTmpValueArray);
} catch(...) {
...
}
}
}
通过源码分析可知 setCurrentPlayTime 才是属性动画真正的发起方法, 最终会调用 PropertyValuesHolder.setAnimatedValue 使用反射去调用相应的方法, 去改变 View 的动画
总结
通过上面的两大部分的源码分析, 对属性动画有了大体的认识, 其中还有很多细节没有去深究, 但可以从整体上了解了属性动画的工作流程









网友评论