一. 简介

1.作用

一个接口,用来设置 属性值 从初始值过渡到结束值 的变化具体数值。

2.插值器与估值器区别

  • 插值器(Interpolator)决定 值 的变化规律(匀速、加速 等等),即决定的是变化趋势;而接下来的具体变化数值则交给估值器。

  • 估值器属性动画特有的属性。

二. 系统的估值器

1.IntEvaluator:以整型的形式从初始值 - 结束值 进行过渡

1
2
3
4
5
6
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}

2.FloatEvaluator:以浮点型的形式从初始值 - 结束值 进行过渡

1
2
3
4
5
6
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);
}
}

3.ArgbEvaluator:以Argb类型的形式从初始值 - 结束值 进行过渡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class ArgbEvaluator implements TypeEvaluator {
private static final ArgbEvaluator sInstance = new ArgbEvaluator();

@UnsupportedAppUsage
public static ArgbEvaluator getInstance() {
return sInstance;
}

public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
float startA = ((startInt >> 24) & 0xff) / 255.0f;
float startR = ((startInt >> 16) & 0xff) / 255.0f;
float startG = ((startInt >> 8) & 0xff) / 255.0f;
float startB = ( startInt & 0xff) / 255.0f;

int endInt = (Integer) endValue;
float endA = ((endInt >> 24) & 0xff) / 255.0f;
float endR = ((endInt >> 16) & 0xff) / 255.0f;
float endG = ((endInt >> 8) & 0xff) / 255.0f;
float endB = ( endInt & 0xff) / 255.0f;

// convert from sRGB to linear
startR = (float) Math.pow(startR, 2.2);
startG = (float) Math.pow(startG, 2.2);
startB = (float) Math.pow(startB, 2.2);

endR = (float) Math.pow(endR, 2.2);
endG = (float) Math.pow(endG, 2.2);
endB = (float) Math.pow(endB, 2.2);

// compute the interpolated color in linear space
float a = startA + fraction * (endA - startA);
float r = startR + fraction * (endR - startR);
float g = startG + fraction * (endG - startG);
float b = startB + fraction * (endB - startB);

// convert back to sRGB in the [0..255] range
a = a * 255.0f;
r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
}
}

三. 自定义的估值器

1.本质

根据 插值器计算出当前属性值改变的百分比 & 初始值 & 结束值 来计算 当前属性具体的数值

2.具体实现方式

实现 TypeEvaluator接口 & 重写evaluate()

1
2
3
4
5
6
7
8
9
10
11
12
public interface TypeEvaluator<T> {
/**
* fraction:插值器getInterpolation()的返回值 表示动画完成度
* startValue:动画的初始值
* endValue:动画的结束值
*/
public T evaluate(float fraction, T startValue, T endValue);
}

// 特别注意:插值器的input值 和 估值器fraction有什么关系呢?
// input的值决定了fraction的值:input值经过计算后传入到插值器的getInterpolation()
// 然后通过实现getInterpolation()中的逻辑算法,根据input值来计算出一个返回值,而这个返回值就是fraction了

在学习自定义估值器前,我们先来看一个已经实现好的系统内置差值器:浮点型估值器器:FloatEvaluator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FloatEvaluator implements TypeEvaluator {  
// FloatEvaluator实现了TypeEvaluator接口

// 重写evaluate()
public Object evaluate(float fraction, Object startValue, Object endValue) {
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
float startFloat = ((Number) startValue).floatValue();

return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
// 初始值 过渡 到结束值 的算法是:
// 1. 用结束值减去初始值,算出它们之间的差值
// 2. 用上述差值乘以fraction系数
// 3. 再加上初始值,就得到当前动画的值
}
}

自定义实现的模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 实现TypeEvaluator接口
public class ObjectEvaluator implements TypeEvaluator{

// 复写evaluate()
// 在evaluate()里写入对象动画过渡的逻辑
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值

.. // 写入对象动画过渡的逻辑

return value;
// 返回对象动画过渡的逻辑计算后的值
}

四. 实际的例子

我们先自定义一个TypeEvaluator:PointEvaluator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class PointEvaluator implements TypeEvaluator {

@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//将动画的初始值和结束值强制转化为Point
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;

//根据fraction计算当前点的x和y

float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());

//封装成对象返回
return new Point(x,y);
}
}

自定义一个View:MyView,用来使用我们的估值器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class MyView extends View {

//圆的半径
public static final float RADIUS = 70f;

//当前点的坐标
private Point currentPoint;

//绘图画笔
private Paint paint;

/**
* 构造方法
* @param context
* @param attrs
*/
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);

//初始化画笔
paint = new Paint(Paint.ANTI_ALIAS_FLAG);

//设置画笔颜色
paint.setColor(Color.MAGENTA);
}

//重绘
@Override
protected void onDraw(Canvas canvas) {
//判断当前点是否为空(即是否是第一次)
if (currentPoint == null){
//初始化点
currentPoint = new Point(RADIUS,RADIUS);

//画圆 以(RADIUS,RADIUS)为圆心,RADIUS为半径画圆
canvas.drawCircle(currentPoint.getX(),currentPoint.getY(),RADIUS,paint);

//动画开始的点和动画结束的点
Point startPoint = new Point(RADIUS,RADIUS);
Point endPoint = new Point(700,700);

//创建动画
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(),startPoint,endPoint);

//设置动画开始的时间
valueAnimator.setDuration(8000);

//监听更新,手动赋值
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//将更新的值传入变量存储
currentPoint = (Point) animation.getAnimatedValue();

//刷新界面 进入else部分重绘
invalidate();
}
});

//开启动画
valueAnimator.start();
}else {
//重绘
canvas.drawCircle(currentPoint.getX(),currentPoint.getY(),RADIUS,paint);
}
}
}

每次动画更新的时候,就重绘视图,每次都是重绘的一个圆,只不过这个圆半径固定为RADIUS,圆心坐标是根据ValueAnimator监听更新时间中传递的值设置。