效果图



使用方式

1
2
3
4
5
6
7
8
9
<CircularProgressView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="30dp"
app:backColor="@color/colorPrimary"
app:backWidth="20dp"
app:progColor="@color/colorAccent"
app:progWidth="30dp"
app:progress="65" />

核心代码

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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/**
* 圆形进度条控件
* Author: JueYes jueyes_1024@163.com
* Time: 2019-08-07 15:38
*/
public class CircularProgressView extends View {

private Paint mBackPaint, mProgPaint; // 绘制画笔
private RectF mRectF; // 绘制区域
private int[] mColorArray; // 圆环渐变色
private int mProgress; // 圆环进度(0-100)

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

public CircularProgressView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public CircularProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@SuppressLint("Recycle")
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircularProgressView);

// 初始化背景圆环画笔
mBackPaint = new Paint();
mBackPaint.setStyle(Paint.Style.STROKE); // 只描边,不填充
mBackPaint.setStrokeCap(Paint.Cap.ROUND); // 设置圆角
mBackPaint.setAntiAlias(true); // 设置抗锯齿
mBackPaint.setDither(true); // 设置抖动
mBackPaint.setStrokeWidth(typedArray.getDimension(R.styleable.CircularProgressView_backWidth, 5));
mBackPaint.setColor(typedArray.getColor(R.styleable.CircularProgressView_backColor, Color.LTGRAY));

// 初始化进度圆环画笔
mProgPaint = new Paint();
mProgPaint.setStyle(Paint.Style.STROKE); // 只描边,不填充
mProgPaint.setStrokeCap(Paint.Cap.ROUND); // 设置圆角
mProgPaint.setAntiAlias(true); // 设置抗锯齿
mProgPaint.setDither(true); // 设置抖动
mProgPaint.setStrokeWidth(typedArray.getDimension(R.styleable.CircularProgressView_progWidth, 10));
mProgPaint.setColor(typedArray.getColor(R.styleable.CircularProgressView_progColor, Color.BLUE));

// 初始化进度圆环渐变色
int startColor = typedArray.getColor(R.styleable.CircularProgressView_progStartColor, -1);
int firstColor = typedArray.getColor(R.styleable.CircularProgressView_progFirstColor, -1);
if (startColor != -1 && firstColor != -1) mColorArray = new int[]{startColor, firstColor};
else mColorArray = null;

// 初始化进度
mProgress = typedArray.getInteger(R.styleable.CircularProgressView_progress, 0);
typedArray.recycle();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int viewWide = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
int viewHigh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
int mRectLength = (int) ((viewWide > viewHigh ? viewHigh : viewWide) - (mBackPaint.getStrokeWidth() > mProgPaint.getStrokeWidth() ? mBackPaint.getStrokeWidth() : mProgPaint.getStrokeWidth()));
int mRectL = getPaddingLeft() + (viewWide - mRectLength) / 2;
int mRectT = getPaddingTop() + (viewHigh - mRectLength) / 2;
mRectF = new RectF(mRectL, mRectT, mRectL + mRectLength, mRectT + mRectLength);

// 设置进度圆环渐变色
if (mColorArray != null && mColorArray.length > 1)
mProgPaint.setShader(new LinearGradient(0, 0, 0, getMeasuredWidth(), mColorArray, null, Shader.TileMode.MIRROR));
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(mRectF, 0, 360, false, mBackPaint);
canvas.drawArc(mRectF, 275, 360 * mProgress / 100, false, mProgPaint);
}

// ---------------------------------------------------------------------------------------------

/**
* 获取当前进度
*
* @return 当前进度(0-100)
*/
public int getProgress() {
return mProgress;
}

/**
* 设置当前进度
*
* @param progress 当前进度(0-100)
*/
public void setProgress(int progress) {
this.mProgress = progress;
invalidate();
}

/**
* 设置当前进度,并展示进度动画。如果动画时间小于等于0,则不展示动画
*
* @param progress 当前进度(0-100)
* @param animTime 动画时间(毫秒)
*/
public void setProgress(int progress, long animTime) {
if (animTime <= 0) setProgress(progress);
else {
ValueAnimator animator = ValueAnimator.ofInt(mProgress, progress);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (int) animation.getAnimatedValue();
invalidate();
}
});
animator.setInterpolator(new OvershootInterpolator());
animator.setDuration(animTime);
animator.start();
}
}

/**
* 设置背景圆环宽度
*
* @param width 背景圆环宽度
*/
public void setBackWidth(int width) {
mBackPaint.setStrokeWidth(width);
invalidate();
}

/**
* 设置背景圆环颜色
*
* @param color 背景圆环颜色
*/
public void setBackColor(@ColorRes int color) {
mBackPaint.setColor(ContextCompat.getColor(getContext(), color));
invalidate();
}

/**
* 设置进度圆环宽度
*
* @param width 进度圆环宽度
*/
public void setProgWidth(int width) {
mProgPaint.setStrokeWidth(width);
invalidate();
}

/**
* 设置进度圆环颜色
*
* @param color 景圆环颜色
*/
public void setProgColor(@ColorRes int color) {
mProgPaint.setColor(ContextCompat.getColor(getContext(), color));
mProgPaint.setShader(null);
invalidate();
}

/**
* 设置进度圆环颜色(支持渐变色)
*
* @param startColor 进度圆环开始颜色
* @param firstColor 进度圆环结束颜色
*/
public void setProgColor(@ColorRes int startColor, @ColorRes int firstColor) {
mColorArray = new int[]{ContextCompat.getColor(getContext(), startColor), ContextCompat.getColor(getContext(), firstColor)};
mProgPaint.setShader(new LinearGradient(0, 0, 0, getMeasuredWidth(), mColorArray, null, Shader.TileMode.MIRROR));
invalidate();
}

/**
* 设置进度圆环颜色(支持渐变色)
*
* @param colorArray 渐变色集合
*/
public void setProgColor(@ColorRes int[] colorArray) {
if (colorArray == null || colorArray.length < 2) return;
mColorArray = new int[colorArray.length];
for (int index = 0; index < colorArray.length; index++)
mColorArray[index] = ContextCompat.getColor(getContext(), colorArray[index]);
mProgPaint.setShader(new LinearGradient(0, 0, 0, getMeasuredWidth(), mColorArray, null, Shader.TileMode.MIRROR));
invalidate();
}
}

自定义属性

res/vasues/attrs.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircularProgressView">
<attr name="backWidth" format="dimension" /> <!--背景圆环宽度-->
<attr name="progWidth" format="dimension" /> <!--进度圆环宽度-->
<attr name="backColor" format="color" /> <!--背景圆环颜色-->
<attr name="progColor" format="color" /> <!--进度圆环颜色-->
<attr name="progStartColor" format="color" /> <!--进度圆环开始颜色-->
<attr name="progFirstColor" format="color" /> <!--进度圆环结束颜色-->
<attr name="progress" format="integer" /> <!--圆环进度-->
</declare-styleable>
</resources>

原文链接

https://www.jianshu.com/p/93d9a2a65bde