Android View之扇形进度动画

(一)扇形进度思路

1、绘制边界

2、绘制左半圆

1
2
3
4
5
6
7
// 根据当前进度算出进度条的位置
// (思路:进度关联进度条位置,进而关联到圆心角)
mCurrentProgressPosition = mProgress * mProgressWidth / TOTAL_PROGRESS;
// 算出圆心角
float angle = (float) Math.toDegrees(Math.acos((mArcRadius - mCurrentProgressPosition) / mArcRadius));
// 再根据进度绘制扇形
canvas.drawArc(mArcRectF, 180 - angle, 2 * angle, false, mPaint);

3、绘制右边矩形

1
2
3
4
5
6
7
// 绘制左边半圆
canvas.drawArc(mArcRectF, 90, 180, false, mPaint);
// 更新矩形右边坐标
mRectF.right = mLeftMargin + mCurrentProgressPosition;
// 再绘制右边矩形
//(思路:通过关联的进度不断更新待绘制的矩形区域)
canvas.drawRect(mRectF, mPaint);

4、暴露接口、更新数据及动画

(二)扇形进度实现

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
/**
* 带扇形的进度动画
*
* @author [*昨日重现*] lhy_ycu@163.com
* @since version 1.0
*/
public class FanProgressView extends View {
private static final int TOTAL_PROGRESS = 100;

// 当前进度
private int mProgress;
// 进度条宽度
private float mProgressWidth;
// 当前进度条的位置
private float mCurrentProgressPosition;
// 扇形半径
private float mArcRadius;
// 左右边距
private int mLeftMargin;
private int mRightMargin;

// 扇形区域
private RectF mArcRectF;
// 矩形区域
private RectF mRectF;

private Paint mPaint;

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

public FanProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

private void init(Context context) {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mArcRectF = new RectF();
mRectF = new RectF();

mLeftMargin = DensityUtils.dip2px(context, 10);
mRightMargin = DensityUtils.dip2px(context, 20);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mProgressWidth = w - mLeftMargin - mRightMargin;
mArcRadius = (h - 2 * mLeftMargin) / 2.0f;
mArcRectF.set(mLeftMargin, mLeftMargin, 2 * mArcRadius + mLeftMargin, 2 * mArcRadius + mLeftMargin);
mRectF.set(mArcRadius + mLeftMargin, mLeftMargin, mLeftMargin + mCurrentProgressPosition, 2 * mArcRadius + mLeftMargin);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBoundary(canvas);

// 根据当前进度算出进度条的位置
mCurrentProgressPosition = mProgress * mProgressWidth / TOTAL_PROGRESS;
mPaint.setStyle(Paint.Style.FILL);
if (mCurrentProgressPosition < mArcRadius) { // 左边:半圆弧
// 圆心角
float angle = (float) Math.toDegrees(Math.acos((mArcRadius - mCurrentProgressPosition) / mArcRadius));
mPaint.setColor(Color.YELLOW);
canvas.drawArc(mArcRectF, 180 - angle, 2 * angle, false, mPaint);
} else {// 右边:矩形
// 绘制左边半圆
mPaint.setColor(Color.YELLOW);
canvas.drawArc(mArcRectF, 90, 180, false, mPaint);
mRectF.right = mLeftMargin + mCurrentProgressPosition;
// 绘制右边矩形
mPaint.setColor(Color.GREEN);
canvas.drawRect(mRectF, mPaint);
}
}

/**
* 绘制边界
*/
private void drawBoundary(Canvas canvas) {
canvas.drawColor(Color.LTGRAY);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5F);
mPaint.setColor(Color.RED);
// 绘制左半边弧形
canvas.drawArc(mArcRectF, 90, 180, false, mPaint);
// 绘制右边矩形
canvas.drawLine(mArcRadius + mLeftMargin, mLeftMargin, mProgressWidth + mLeftMargin, mLeftMargin, mPaint);
canvas.drawLine(mArcRadius + mLeftMargin, mLeftMargin + 2 * mArcRadius, mProgressWidth + mLeftMargin, mLeftMargin + 2 * mArcRadius, mPaint);
canvas.drawLine(mProgressWidth + mLeftMargin, mLeftMargin, mProgressWidth + mLeftMargin, mLeftMargin + 2 * mArcRadius, mPaint);
}

/**
* 更新进度
*
* @param progress 当前进度
*/
public void setProgress(int progress) {
this.mProgress = progress;
invalidate();
}

// 方便属性动画更新属性progress的值
public int getProgress() {
return this.mProgress;
}

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

分享