最近项目中用到渐变圆环进度条,自己也写了一下,用到一些知识,以前没有用过,使用过程中有一些问题,在此做一下笔记。

渐变颜色其实用到的是颜色数组,然后根据数组计算来的,当然计算是Android系统进行的,不需要我们手动计算,我们只需要设置颜色数组和颜色值对应位置即可。画圆形渐变用到一个属性:SweepGradient,他的父类是一个Shader,

由官方文档看到他有两个构造函数:

1
2
3
SweepGradient(float cx, float cy, int color0, int color1)
SweepGradient(float cx, float cy, int colors[], float positions[])

  • cx:要画的圆环的中心点x坐标;
  • cy:要画的圆环的中心点y坐标;
  • color0:起始颜色值;
  • color1:结束颜色值;
  • colors[]:颜色数组;
  • positions[]:对应颜色值的位置,与颜色值数组个数相等,里面的值均为(0–1)的数字。

先看一张效果图(图一):

00

这就是一张渐变圆环图,上面的箭头和数字后面解释。

我们主要研究第二个构造函数,颜色数组和颜色位置的使用方法。

首先看一个例子:

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
/**
* 圆形渐变进度条
* 相关知识:
* <p>
* Created by yuchuan on 16/9/29.
*/

public class CircleGradientProgressbar extends View {

private final static int DURATION = 3000;
private int mWidth;
private int mHeight;
private int mDiam;

private int mColorGreen;
private int mColorYellow;
private int mColorRed;

private final float mMaxProgress = 100f;
//默认进度
private int mProgress = 80;

private int mCurrentProgress = 100;
//进图条圆环宽度
private int mProgressStrokeWidth = 10;
//进度条背景画笔
private Paint mCirclePaint;
//进度条画笔
private Paint mProgressPaint;
private Shader mProgressShader;

//画圆所在的距形区域
private RectF mProgressOval;

private ValueAnimator mAnimator;

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

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

private void init() {

mColorGreen = getResources().getColor(R.color.mx_circle_progressbar_green);
mColorYellow = getResources().getColor(R.color.mx_circle_progressbar_orange);
mColorRed = getResources().getColor(R.color.mx_circle_progressbar_red);

mProgressOval = new RectF();

mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(Color.GRAY);

mProgressPaint = new Paint();
//设置抗锯齿
mProgressPaint.setAntiAlias(true);
//设置笔为圆角
// mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint.setStyle(Paint.Style.STROKE);

mAnimator = ValueAnimator.ofFloat(0, 1f);

mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float percent = (float) animation.getAnimatedValue();
if (percent > 0) {
mCurrentProgress = (int) (mProgress * percent);
postInvalidate();
}
}
});

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mWidth = getWidth();
mHeight = getHeight();
mDiam = Math.min(mWidth, mHeight);
mProgressStrokeWidth = mDiam / 6;
drawCircle(canvas);
drawSweepProgressBar(canvas, mWidth / 2, mHeight / 2);
}

private void drawCircle(Canvas canvas) {
canvas.drawArc(mProgressOval, 0, 360, false, mCirclePaint);
}

/**
* 画渐变圆环:
* colorSweep[]: 渐变颜色数组
* position[]: 每个颜色值的相对位置,个数与颜色数组个数相等
* 注:位置与渐变颜色值的设置教程见博客:
*
* @param canvas 画布
* @param cx 圆环中心X坐标
* @param cy 圆环中心Y坐标
*/
private void drawSweepProgressBar(Canvas canvas, int cx, float cy) {

//设置圆环的大小
mProgressOval.top = cy - mDiam / 4;
mProgressOval.left = cx - mDiam / 4;
mProgressOval.bottom = cy + mDiam / 4;
mProgressOval.right = cx + mDiam / 4;

//画渐变颜色
int colorSweep[] = {mColorGreen, mColorYellow, mColorRed};
float position[] = {0f,0.5f,0.7f};

mProgressShader = new SweepGradient(cx, cy, colorSweep, position);
mProgressPaint.setShader(mProgressShader);
mProgressPaint.setStrokeWidth(mProgressStrokeWidth);
canvas.drawArc(mProgressOval, 0, ((float) mCurrentProgress / mMaxProgress) * 360, false, mProgressPaint); // 绘制进度圆弧,这里是蓝色

}

public void setProgress(int progress) {
this.mProgress = progress;
if (mAnimator != null && progress > 0) {
if (mAnimator.isRunning()) {
return;
}
mAnimator.setDuration((long) (DURATION / mMaxProgress * progress));
mAnimator.start();
}
}
}

效果图如下:

01

此时的颜色数组和位置参数为:

1
2
int colorSweep[] = {mColorGreen, mColorYellow, mColorRed};
float position[] = {0f,0.5f,0.7f};

下面我们更改一下颜色值的位置:

1
2
int colorSweep[] = {mColorGreen, mColorYellow, mColorRed};
float position[] = {0.25f,0.5f,0.75f};

效果图如下:

02

对比上面两个图片我们看到随着第一个位置的值的增大,第一个颜色值的渐变色开始位置也在向后移动。此时我们画圆环是从0度开始的,也就是3点钟的位置开始,顺时针开始画圆环。第一个颜色绿色也是从这个位置开始的。那么我们看看如果我改变开始画的位置,有什么变化吗?

我用上面第二组的数据,然后只改变画圆环的初始位置:

1
2
3
int colorSweep[] = {mColorGreen, mColorYellow, mColorRed};
float position[] = {0.25f,0.5f,0.75f};
canvas.drawArc(mProgressOval, 0, ((float) mCurrentProgress / mMaxProgress) * 360, false, mProgressPaint);

效果图如下:

02

显示效果和上面一个是一样的,只是运行时你会发现,圆环是从(图一)0.75那个位置开始顺时针画的,并且开始画的颜色是红色的,由此判断,第一个颜色值是用(图一)0的那个位置顺时针开始计算的,那么如果我想从0.75那个位置开始画并且颜色从绿的开始怎么画,那你需要将开始画的角度改为:-90,然后更改颜色数组和颜色位置数组:

1
2
3
int colorSweep[] = {mColorGreen, mColorGreen, mColorYellow, mColorRed, mColorGreen, mColorGreen};
float position[] = {0.1f, 0.25f, 0.5f, 0.751f, 0.75f, 1f};
canvas.drawArc(mProgressOval, -90, ((float) mCurrentProgress / mMaxProgress) * 360, false, mProgressPaint);

效果图如下:

03

此时我们看到,绿色是从(图一)0.75位置开始的,并且圆环也是从这个位置开始画的,但是此时我的颜色值和位置增加了,主要是后面部分,倒数第二个颜色值是绿色,对应位置是0.75,也是就分段设置颜色值,0.75的位置为绿色,最后一个也是绿色,则说明从0.75之后到1的位置都是绿色,然后0后面的颜色根据位置数组第一个参数开始计算,如果角度不是0就要按照这个计算进行调整。

另外,最后一个例子中相同颜色设置了多个,这个是调节渐变和纯色位置的,也就是相同颜色位置间的颜色是纯色的,不同颜色值中间的颜色是过度的,自己可以调节一下掌握以下技巧。

Github地址:https://github.com/yuchuangu85/OpenSource_MX

Android开发群:192508518

微信公众账号:Code-MX
qr_code_mx

注:本文原创,转载请注明出处,多谢。