背景
开发过程当中,当我们进行上传、下载或者更新等项目需求时,往往需要给用户展示一个进度值用于显示当前的更新状态,便于用户进行操作处理。当原生的控件满足不了展示需要时,就要我们自己定制所需要的展示效果,值此情景时各种各样的自定义进度展示控件便应用而生。以下简单介绍几种常见的显示样式,实现的方式大同小异,大家可以根据自己的需求简单修改配置即可。
效果图:
常见的使用样式
ProgressWheel
使用
1.在attr.xml
中定义属性
<declare-styleable name="ProgressWheel">
<!-- 文本内容 -->
<attr name="pwText" format="string" />
<!-- 文本字体颜色 -->
<attr name="pwTextColor" format="color" />
<!-- 文本字体大小 -->
<attr name="pwTextSize" format="dimension" />
<!-- 进度条颜色 -->
<attr name="pwBarColor" format="color" />
<!-- 进度条宽度 -->
<attr name="pwBarWidth" format="integer" />
<!-- 进度条默认长度 -->
<attr name="pwDefaultProgress" format="integer" />
<!-- 默认轮廓颜色 -->
<attr name="pwRimColor" format="color" />
<!-- 默认轮廓宽度 -->
<attr name="pwRimWidth" format="integer" />
<!-- 圆圈内部的颜色 -->
<attr name="pwCircleInnerColor" format="color" />
<!-- 控制外边缘颜色 -->
<attr name="pwOuterEdgeColor" format="color" />
<!-- 控制外边缘大小 -->
<attr name="pwOuterEdgeSize" format="dimension" />
<!-- 控制内边缘颜色 -->
<attr name="pwInnerEdgeColor" format="color" />
<!-- 控制内边缘大小 -->
<attr name="pwInnerEdgeSize" format="dimension" />
</declare-styleable>
2.布局文件
<com.wiggins.progresswheel.widget.ProgressWheel
android:id="@+id/mProgressWheel"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginTop="@dimen/margin_normal"
app:pwBarColor="@color/red"
app:pwBarWidth="15"
app:pwDefaultProgress="49"
app:pwRimColor="@color/orange"
app:pwRimWidth="15" />
3.java
文件调用
mProgressWheel.setProgress(pg);
4.绘制元素边界
private void setupBounds() {
// 为了保持宽度和长度的一致,我们要获得layout_width和layout_height中较小的一个,从而绘制一个圆
int minValue = Math.min(layoutWidth, layoutHeight);
// 计算在绘制过程中在x,y方向的偏移量
int xOffset = layoutWidth - minValue;
int yOffset = layoutHeight - minValue;
// 间距加上偏移量
paddingTop = this.getPaddingTop() + (yOffset / 2);
paddingBottom = this.getPaddingBottom() + (yOffset / 2);
paddingLeft = this.getPaddingLeft() + (xOffset / 2);
paddingRight = this.getPaddingRight() + (xOffset / 2);
int width = getWidth();
int height = getHeight();
innerEdgeBounds = new RectF(
paddingLeft + (1.5f * barWidth),
paddingTop + (1.5f * barWidth),
width - paddingRight - (1.5f * barWidth),
height - paddingBottom - (1.5f * barWidth));
outerEdgeBounds = new RectF(
paddingLeft + barWidth,
paddingTop + barWidth,
width - paddingRight - barWidth,
height - paddingBottom - barWidth);
innerEdgeContour = new RectF(
outerEdgeBounds.left + (rimWidth / 2.0f) + (outerEdgeSize / 2.0f),
outerEdgeBounds.top + (rimWidth / 2.0f) + (outerEdgeSize / 2.0f),
outerEdgeBounds.right - (rimWidth / 2.0f) - (outerEdgeSize / 2.0f),
outerEdgeBounds.bottom - (rimWidth / 2.0f) - (outerEdgeSize / 2.0f));
outerEdgeContour = new RectF(
outerEdgeBounds.left - (rimWidth / 2.0f) - (innerEdgeSize / 2.0f),
outerEdgeBounds.top - (rimWidth / 2.0f) - (innerEdgeSize / 2.0f),
outerEdgeBounds.right + (rimWidth / 2.0f) + (innerEdgeSize / 2.0f),
outerEdgeBounds.bottom + (rimWidth / 2.0f) + (innerEdgeSize / 2.0f));
}
5.绘制元素属性
private void setupPaints() {
//进度条
barPaint.setColor(barColor);//设置画笔颜色
barPaint.setAntiAlias(true);//设置抗锯齿
barPaint.setStyle(Style.STROKE);//设置画笔为空心
barPaint.setStrokeWidth(barWidth);//设置线宽
//圆环
rimPaint.setColor(rimColor);
rimPaint.setAntiAlias(true);
rimPaint.setStyle(Style.STROKE);
rimPaint.setStrokeWidth(rimWidth);
//环内
circleInnerPaint.setColor(circleInnerColor);
circleInnerPaint.setAntiAlias(true);
circleInnerPaint.setStyle(Style.FILL);
//字体
textPaint.setColor(textColor);
textPaint.setStyle(Style.FILL);
textPaint.setAntiAlias(true);
textPaint.setTextSize(textSize);
//外边缘
outerEdgePaint.setColor(outerEdgeColor);
outerEdgePaint.setAntiAlias(true);
outerEdgePaint.setStyle(Style.STROKE);
outerEdgePaint.setStrokeWidth(outerEdgeSize);
//内边缘
innerEdgePaint.setColor(innerEdgeColor);
innerEdgePaint.setAntiAlias(true);
innerEdgePaint.setStyle(Style.STROKE);
innerEdgePaint.setStrokeWidth(innerEdgeSize);
}
6.绘制视图
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制边界
canvas.drawArc(innerEdgeBounds, 360, 360, false, circleInnerPaint);
canvas.drawArc(outerEdgeBounds, 360, 360, false, rimPaint);
//绘制边缘
canvas.drawArc(outerEdgeContour, 360, 360, false, outerEdgePaint);
canvas.drawArc(innerEdgeContour, 360, 360, false, innerEdgePaint);
//绘制进度
canvas.drawArc(outerEdgeBounds, -90, progress, false, barPaint);
//绘制文字(并让它显示在圆水平和垂直方向的中心处)
float textHeight = textPaint.descent() - textPaint.ascent();
float verticalTextOffset = (textHeight / 2) - textPaint.descent();
for (String line : splitText) {
float horizontalTextOffset = textPaint.measureText(line) / 2;
canvas.drawText(
line,
this.getWidth() / 2 - horizontalTextOffset,
this.getHeight() / 2 + verticalTextOffset,
textPaint);
}
}
RoundProgressBar
使用
1.在attr.xml
中定义属性
<declare-styleable name="RoundProgressBar">
<!-- 圆环颜色 -->
<attr name="roundColor" format="color" />
<!-- 圆环宽度 -->
<attr name="roundWidth" format="float" />
<!-- 进度条颜色 -->
<attr name="progressColor" format="color" />
<!-- 默认进度百分比 -->
<attr name="progressRatio" format="float" />
<!-- 字体颜色 -->
<attr name="textColors" format="color" />
<!-- 字体大小 -->
<attr name="textSizes" format="dimension" />
<!-- 是否显示进度百分比 -->
<attr name="textIsShow" format="boolean" />
</declare-styleable>
2.布局文件
<com.wiggins.progresswheel.widget.RoundProgressBar
android:id="@+id/mRoundProgressBar"
android:layout_width="150dp"
android:layout_height="150dp"
app:progressColor="@color/blue"
app:roundColor="@color/red" />
3.java
文件调用
mRoundProgressBar.setProgress(new float[]{getProgress(56), getProgress(90),
getProgress(120), getProgress(88), getProgress(80)},
new String[]{"#A0DD2A", "#FFAF8B", "#36D9F1", "#FFD71C", "#A89AFF"});
4.绘制元素边界
private void setupBounds() {
int minValue = Math.min(getWidth(), getHeight());
int centre = minValue / 2; // 获取圆心的x坐标
int radius = (int) (centre - mRoundWidth / 2); // 圆环的半径
mBounds = new RectF(centre - radius, centre - radius, centre + radius, centre + radius);
}
5.绘制元素属性
private void setupPaints() {
mRoundPaint.setColor(mRoundColor);// 设置画笔颜色
mRoundPaint.setAntiAlias(true); // 消除锯齿
mRoundPaint.setStyle(Style.STROKE); // 设置空心
mRoundPaint.setStrokeWidth(mRoundWidth);// 设置线宽
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setAntiAlias(true);
mProgressPaint.setStrokeWidth(mRoundWidth);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Style.STROKE);
}
6.绘制视图
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制边界
canvas.drawArc(mBounds, 0, 360, false, mRoundPaint);
// 绘制进度百分比
int percent = Math.round((mProgressRatio / 360) * 100);
// 测量字体宽度
float textWidth = mTextPaint.measureText(percent + "%");
// 绘制的起点X轴坐标:画布宽度的一半 - 文字宽度的一半
int baseX = (int) (canvas.getWidth() / 2 - textWidth / 2);
// 绘制的起点Y轴坐标:画布高度的一半 - 文字总高度的一半
int baseY = (int) ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2));
// 绘制进度
float start = -90;
if (mRatio != null) {
for (int i = 0; i < mRatio.length; i++) {
mProgressPaint.setColor(Color.parseColor(mColors[i]));// 进度的颜色
canvas.drawArc(mBounds, start, mRatio[i], false, mProgressPaint);
start += mRatio[i];
}
} else {
mProgressPaint.setColor(mProgressColor); // 进度的颜色
canvas.drawArc(mBounds, start, mProgressRatio, false, mProgressPaint);
if (mTextIsShow) {
canvas.drawText(percent + "%", baseX, baseY, mTextPaint);
}
}
}
RingProgressBar
使用
1.在attr.xml
中定义属性
<declare-styleable name="RingProgressBar">
<!-- 圆环颜色 -->
<attr name="ringColor" format="color" />
<!-- 圆环宽度 -->
<attr name="ringWidth" format="dimension" />
<!-- 圆环是否空心 -->
<attr name="ringIsStroke" format="boolean" />
<!-- 进度颜色 -->
<attr name="ringProgressColor" format="color" />
<!-- 字体颜色 -->
<attr name="textColor" format="color" />
<!-- 字体大小 -->
<attr name="textSize" format="dimension" />
<!-- 是否显示中间的进度值 -->
<attr name="textIsDisplayable" format="boolean" />
<!-- 最大进度值 -->
<attr name="maxProgress" format="integer" />
<!-- 进度条的风格:实心或者空心 -->
<attr name="ringProgressStyle">
<enum name="STROKE" value="0" />
<enum name="FILL" value="1" />
</attr>
</declare-styleable>
2.布局文件
<com.wiggins.progresswheel.widget.RingProgressBar
android:id="@+id/mRingProgressBar"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginLeft="@dimen/margin_normal"
app:maxProgress="100"
app:ringColor="@color/blue"
app:ringIsStroke="false"
app:ringProgressColor="@color/orange"
app:ringWidth="7dp" />
3.java
文件调用
mRingProgressBar.setCurrentProgress(63);
4.绘制视图
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 绘制默认圆环
*/
int centre = getWidth() / 2; // 获取圆心的x坐标
int radius = (int) (centre - mRingWidth / 2); // 圆环的半径
mRingPaint.setColor(mRingColor); // 圆环颜色
mRingPaint.setStrokeWidth(mRingWidth); // 圆环宽度
mRingPaint.setAntiAlias(true); // 消除锯齿
if (mRingIsStroke) {
mRingPaint.setStyle(Paint.Style.STROKE); // 设置空心
} else {
mRingPaint.setStyle(Paint.Style.FILL); // 设置实心
}
canvas.drawCircle(centre, centre, radius, mRingPaint); // 画出圆环
/**
* 绘制进度百分比
*/
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setAntiAlias(true);
// 进度百分比
int percent = (int) (((float) mCurrentProgress / (float) mMaxProgress) * 100);
// 测量字体宽度
float textWidth = mTextPaint.measureText(percent + "%");
// 绘制的起点X轴坐标:画布宽度的一半 - 文字宽度的一半
int baseX = (int) (canvas.getWidth() / 2 - textWidth / 2);
// 绘制的起点Y轴坐标:画布高度的一半 - 文字总高度的一半
int baseY = (int) ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2));
if (mTextIsDisplayable && mRingProgressStyle == STROKE) {
canvas.drawText(percent + "%", baseX, baseY, mTextPaint);
}
/**
* 绘制进度的圆弧
*/
mProgressPaint.setStrokeWidth(mRingWidth);
mProgressPaint.setColor(mRingProgressColor);
mProgressPaint.setAntiAlias(true);
RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定义的圆弧的形状和大小的界限
switch (mRingProgressStyle) {
case STROKE: {
mProgressPaint.setStyle(Paint.Style.STROKE);
canvas.drawArc(oval, 270, 360 * mCurrentProgress / mMaxProgress, false, mProgressPaint); // 根据进度画圆弧
break;
}
case FILL: {
mProgressPaint.setStyle(Paint.Style.FILL_AND_STROKE);
if (mCurrentProgress != 0) {
canvas.drawArc(oval, 270, 360 * mCurrentProgress / mMaxProgress, true, mProgressPaint); // 根据进度画圆弧
}
break;
}
}
}
项目地址 ☞ 传送门