在上一篇文章中,我们对ObjectAnimator.ofFloat方法进行了分析,其中生成PropertyValuesHolder对象的方法PropertyValuesHolder.ofFloat("", values)我们并没有进去看,这一篇我们就看看这个"holder"生成的时候究竟做了什么事。
首先我们进入ObjectAnimator.ofFloat方法:
//PropertyValuesHolder.java
public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
return new FloatPropertyValuesHolder(propertyName, values);
}
这里新建了一个FloatPropertyValuesHolder,类似于工厂模式,对不同的需要产生不同类型的PropertyValuesHolder对象,可以是int,float或者其他对象类型(提供了转换器),我们这里不做细致研究,还是沿着主线路往下看:
//FloatPropertyValuesHolder.java
public FloatPropertyValuesHolder(String propertyName, float... values) {
super(propertyName);
setFloatValues(values);
}
...
//PropertyValuesHolder.java
//super(propertyName)进了这里
private PropertyValuesHolder(String propertyName) {
mPropertyName = propertyName;
}
...
//FloatPropertyValuesHolder.java
//setFloatValues(values)走了这里
@Override
public void setFloatValues(float... values) {
super.setFloatValues(values);
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}
这里主要讲属性名保存了起来,并且设置了一个"KeyFrameSet",即关键帧集合,很明显,关键帧的生成代码就在super.setFloatValues(values)里,我们进去在一探究竟:
//PropertyValuesHolder.java
public void setFloatValues(float... values) {
mValueType = float.class;
mKeyframes = KeyframeSet.ofFloat(values);
}
这个keyframeSet的构建形式和PropertyValuesHolder的形式看起来类似,当然,实际也是如此:
//KeyFrameSet.java
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);
}
我们看到这段代码的大体作用是根据规则生成了一系列的KeyFrames()关键帧),并且将其添加到了KeyFrameSet(即关键帧集合),那么这个关键帧是什么呢,参照官方说法:
//KeyFrames.java
/**
* This class holds a time/value pair for an animation. The Keyframe class is used
* by {@link ValueAnimator} to define the values that the animation target will have over the course
* of the animation. As the time proceeds from one keyframe to the other, the value of the
* target object will animate between the value at the previous keyframe and the value at the
* next keyframe.
*...
*/
按照官方的说法,KeyFrames是一个保存动画中时间/值的键值对,用于定义动画目标进行过程中的过程值。要进行动画的目标将会依照这些KeyFrames进行动画。
通俗一点的说,比如最终有三个KeyFrames,第一个是0.0,值是100,第二个是0.5,值是200,第三个是是1.0,值是300;动画目标就会根据这个KeyFrames在最开始的时候得到100的值,在时间进行到一半的时候得到200的值,在时间结束的时候获得300的值。其实KeyFrames就是代表了动画进行的关键帧数,为动画的实际执行提供了“变化的方向”, 而KeyFramesSet代表了动画进行的关键帧数集合。了解了这些,我们在回来分析下KeyFrameSet.ofFloat的代码:
首先我们知道传入的参数是我们之前的变化的一系列值,例如在最开始的示例中,我们传入的是0.8f,1.0f;然后int numKeyframes = values.length;记录了传入值的数量,接下来生成了一个KeyFrames的数组(最终这个数组用于初始化KeyFrameSet),该数组的最小值为2,也就代表着最小要有两个值来控制这次变化。之后是一个判断,用于判断当前传入值的数量是1还是大于1,如果是1的话
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
就通过这两句生成一个从0到values[0]变化的帧,如果大于1(小于1不会到这里),则根据numKeyframes ,来生成numKeyFrames个帧,每个帧的进度都是通过当前帧的位置/帧的总数来平均分:
keyframes[i] =(FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
(在这个过程中,如果传入的值不符合条件,会记录一个badValues标志代表本次的值有问题)
if (Float.isNaN(values[i])) {
badValue = true;
}
最终,将生成的所有KeyFrames放到KeyFramesSet中进行保存,然后将这个set存放到mFloatKeyframes中。
我们在贴出Keyframe.ofFloat();的实现,也是个初始化的过程:
FloatKeyframe(float fraction, float value) {
mFraction = fraction;
mValue = value;
mValueType = float.class;
mHasValue = true;
}
至此,我们就把属性动画的初始化过程看完了,总体理下来我们可以看出大体的初始化过程如下:
- ObjectAnimation.ofFloat->传递要进行动画的对象,要改变的属性名,一系列的属性值
- 属性名+属性值存放到了PropertyValueHolder中,这个用来代表一个属性的变化情况
- 如果初始化时使用ObjectAnimation.ofPropertyValuesHolder则相当于多个属性的变化情况(类似于动画集合的效果)
- PropertyValues.setValues()->进行变化值的设置,生成关于这系列值的关键帧
- mKeyframes ->该PropertyValues中变化值生成的关键帧集合
下一篇文章我们将开始分析属性动画start的过程。
其他部分链接
[Android属性动画源码分析(一)]
[Android属性动画源码分析(二)]
[Android属性动画源码分析(四)]