在属性动画中对值的计算需要插值器和估值器的参与,这样能产生更加丰富的动画
一、插值器
插值器其实是变化快慢的一个衡量标准,根据时间流逝的比例,来得出属性值变化的比例,具体来看一下插值器
的源码:
public interface TimeInterpolator {
/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation time.
*
* @param input A value between 0 and 1.0 indicating our current point
* in the animation where 0 represents the start and 1.0 represents
* the end
* @return The interpolation value. This value can be more than 1.0 for
* interpolators which overshoot their targets, or less than 0 for
* interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}
这是一个接口,只有一个方法,input就是时间的流逝,返回的就是属性值变化的程度
其直接继承接口是Interpolator,这仍然是一个接口,Interpolator就有很多实现类了:匀速、加速、减速等等插值器
public class LinearInterpolator implements Interpolator {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
}
//AccelerateInterpolator
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
//DecelerateInterpolator
public float getInterpolation(float input) {
float result;
if (mFactor == 1.0f) {
result = (float)(1.0f - (1.0f - input) * (1.0f - input));
} else {
result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
}
return result;
}
从上面可以抽象出三个函数:
LinearInterpolator:result = input
AccelerateInterpolator:result = input^2
DecelerateInterpolator: result = 1-(1-input)^2
那么上面的result是如何反应变化速度的呢?
就是对input求导,也就是对时间求导,求导之后:
LinearInterpolator:result导数 = 1
AccelerateInterpolator:result导数 = 2 * input
DecelerateInterpolator: result导数 = 2*(1-input)
可以看出当input由0变成1时,LinearInterpolator导数不变,也就是匀速;AccelerateInterpolator导数变大,也就是
速度越来越快;DecelerateInterpolator导数越来越小,也就是速度越来越慢。
二、估值器
有了插值器得到的属性值的变化程度之后,就要算出具体的属性值了,比如从start变化到最终的end,某一时刻,
插值器得到变化程度为result,那么
属性值=start+(end-start)*result
让我们看一下源码中估值器都是如何计算属性值的:
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
public class FloatEvaluator implements TypeEvaluator<Number> {
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}
属性估值器唯一要实现的方法是evaluate方法,如上,源码中的估值器“估值”过程都是使用我们所讲的方法,那既然
方法都一样,为什么不使用同一个估值器呢?
原因是有些属性并不能直接按照上面的方法进行计算,比如:将View的背景色由红色变成蓝色,这种属性就不能简单
的使用上面的方法,因为这个属性并不是使用一个数值就能简单描述的,还好google工程师专门为颜色变化写了一个估值器
public class ArgbEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
}
仔细观察其实也是我们上面所说的方法,但是将argb各个数值进行计算,然后组合出来一个值。
总结
插值器就是反应属性变化的快慢,具体快慢的标准可以由插值器函数求导得到;估值器具体计算属性值,一般计算的方法就是
start+(end-start)*fraction