Android Animator之ValueAnimator

(一)Android 动画概述

补间动画(Tweened Animation):只会改变View的显示效果,不会改变View的真正属性(比如:按钮经补间动画平移后,点击平移后位置上按钮是无效的)。

逐帧动画(Frame-by-Frame Animation):只是将一个完整的动画拆分成一些单独的图片,然后再将它们按顺序连贯起来进行播放。

ValueAnimator:只能用于计算在指定时间内,初始值到结束值之间(中间可能有多个过渡值)平滑的动画过渡。

ObjectAnimator:可以直接对任意对象的任意属性进行动画操作。--功能强大

View可以直接执行动画: view.animate().x(500).y(500).setDuration(5000);

(二)TypeEvaluator 用法

TypeEvaluator:作用是告诉动画系统如何从初始值过渡到结束值。

自定义一个TypeEvaluator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* PointEvaluator:告诉动画系统起始点到结束点的过渡机制
*
* @author [*昨日重现*] lhy_ycu@163.com
* @since version 1.0
*/
public class PointEvaluator implements TypeEvaluator<Point> {

/**
* 计算初始值到结束值的过渡
*
* @param fraction 动画完成进度
* @param startValue 初始值(对象)
* @param endValue 结束值(对象)
*/
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
float floatX = startValue.x + fraction * (endValue.x - startValue.x);
float floatY = startValue.y + fraction * (endValue.y - startValue.y);
DebugLog.e("floatX:" + floatX + ", floatY:" + floatY);

return new Point((int) floatX, (int) floatY);
}
}

执行两个点之间的动画过渡:

1
2
3
4
5
6
7
8
9
10
11
12
13
PointEvaluator evaluator = new PointEvaluator();
Point startPoint = new Point(0, 0);
Point endPoint = new Point(10, 10);
ValueAnimator valueAnimator = ValueAnimator.ofObject(evaluator, startPoint, endPoint);
valueAnimator.setDuration(10000L);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Point point = (Point) animation.getAnimatedValue();
DebugLog.e("point:" + point.toString());// 新的过渡点
}
});
valueAnimator.start();

(三)ValueAnimator 实例

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
* ValueAnimator之画圆动画过渡轨迹
*
* @author [*昨日重现*] lhy_ycu@163.com
* @since version 1.0
*/
public class ValueAnimatorView extends View {
private Paint mPaint;
private Path mDstPath;// 目标路径
private PathMeasure mPathMeasure;
private ValueAnimator mValueAnimator;// 值动画
private Context mContext;

private int mWidth, mHeight;// 控件大小
private float mCirclePerimeter;// 圆的周长
private float mStopD;// 截取的结束位置距离Path起点的路径(轨迹)长度

public ValueAnimatorView(Context context) {
this(context, null);
}

public ValueAnimatorView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}

private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(DensityUtils.dip2px(mContext, 15));

Path path = new Path();
path.addCircle(0, 0, DensityUtils.dip2px(mContext, 100), Path.Direction.CW);
mPathMeasure = new PathMeasure(path, false);
mCirclePerimeter = mPathMeasure.getLength();

mDstPath = new Path();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = measureDimension(DensityUtils.dip2px(mContext, 250), widthMeasureSpec);
int height = measureDimension(DensityUtils.dip2px(mContext, 250), heightMeasureSpec);
setMeasuredDimension(width, height);// 保存最终测量的宽高
}

private int measureDimension(int defaultSize, int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;// 指定大小
} else {
result = defaultSize;// 默认大小
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.mWidth = w;
this.mHeight = h;
}

/**
* 开始动画
*/
public void startAnimation() {
if (mValueAnimator != null) {
if (mValueAnimator.isRunning()) {
return;
}
mValueAnimator = null;
}
mValueAnimator = ValueAnimator.ofFloat(0, 1F);// ValueAnimator.ofFloat(0, 0.8F, 1F);// 后面20%变慢
mValueAnimator.setDuration(3000L);// 每次持续3s(默认300ms)
mValueAnimator.setRepeatCount(2);// 重复 2+1 次; 总时间:mValueAnimator.getTotalDuration()
mValueAnimator.setRepeatMode(ValueAnimator.REVERSE);// 反向重复
mValueAnimator.setInterpolator(new AccelerateInterpolator());// 动画插入器:Interpolator插值器定义动画的变化率。
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();// [0.0f, 1.0f]
mStopD = mCirclePerimeter * value;
invalidate();
}
});
mValueAnimator.setStartDelay(1000L);// 延时1s执行动画
// mValueAnimator.reverse();// 反向执行
mValueAnimator.start();
}

/**
* 暂停动画
*/
public void pauseAnimation() {
if (mValueAnimator != null) {
if (mValueAnimator.isRunning()) {
mValueAnimator.pause();
}
}
}

/**
* 继续动画
*/
public void resumeAnimation() {
if (mValueAnimator != null) {
if (mValueAnimator.isRunning()) {
mValueAnimator.resume();
}
}
}

/**
* 结束动画
*/
public void endAnimation() {
if (mValueAnimator != null) {
if (mValueAnimator.isRunning()) {
mValueAnimator.end();
}
mValueAnimator = null;
}
}

/**
* 重启动画
*/
public void restartAnimation() {
if (mValueAnimator != null) {
if (mValueAnimator.isRunning()) {
mValueAnimator.cancel();
}
}
startAnimation();
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
endAnimation();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(mWidth / 2, mHeight / 2);
canvas.drawColor(Color.CYAN);

mDstPath.reset();
if (mPathMeasure.getSegment(0, mStopD, mDstPath, true)) {
canvas.drawPath(mDstPath, mPaint);
}
}

}
Hawky wechat
欢迎订阅我的微信公众号
坚持原创技术分享,您的支持将鼓励我继续创作!

分享