Android:自定义圆形ProgressBar,中间有空格

标签 android android-canvas android-custom-view android-progressbar ondraw

我正在尝试创建一个包含 Circle 的自定义 View ,并且在其中,我必须在运行时包含部分,如下图所示。我在 onDraw 方法中尝试了很多东西,但没有成功。我什至试过https://github.com/donvigo/CustomProgressControls .基本上,我想给出一些部分,然后在每个部分中我可以根据需要选择颜色。

enter image description here

我正在寻找应该有间隙/空间的 ProgressBar,如图所示;在圆圈之间。例如,如果我给出了 5 个部分,其中 3 个应该是“完整的”,它应该将前 3 个涂成红色,将另外 2 个涂成绿色。

画画我是这样做的:

private void initExternalCirclePainter() {
    internalCirclePaint = new Paint(); 
    internalCirclePaint.setAntiAlias(true);    
    internalCirclePaint.setStrokeWidth(internalStrokeWidth);  
    internalCirclePaint.setColor(color); 
    internalCirclePaint.setStyle(Paint.Style.STROKE);
    internalCirclePaint.setPathEffect(new DashPathEffect(new float[]{dashWith, dashSpace}, dashSpace));
} 

最佳答案

我可能来晚了一点,但我实际上写了一个自定义组件,它有 2 个环,看起来与您想要实现的非常相似。您可以轻松卸下外圈。最后得到的图片:

enter image description here

这是类:

public class RoundedSectionProgressBar extends View {
// The amount of degrees that we wanna reserve for the divider between 2 sections
private static final float DIVIDER_ANGLE = 7;
public static final float DEGREES_IN_CIRCLE = 360;
public static final int PADDING = 18;
public static final int PADDING2 = 12;

protected final Paint paint = new Paint();
protected final Paint waitingPaint = new Paint();
protected final Paint backgroundPaint = new Paint();
private int totalSections = 5;
private int fullSections = 2;
private int waiting = 3; // The outer ring. You can omit this
private RectF rect = new RectF();

public RoundedSectionProgressBar(Context context) {
    super(context);
    init(context, null);
}

public RoundedSectionProgressBar(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
}

public RoundedSectionProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs);
}

private void init(Context context, AttributeSet attrs) {
    // Can come from attrs if need be?
    int strokeWidth = 3;
    setupPaint(context, strokeWidth, paint, R.color.filled_color_inner_ring);
    setupPaint(context, strokeWidth, waitingPaint, R.color.empty_color_inner_ring);
    setupPaint(context, strokeWidth, backgroundPaint, R.color.filled_color_outer_ring);
}

private void setupPaint(Context context, int strokeWidth, Paint backgroundPaint, int colorRes) {
    backgroundPaint.setStrokeCap(Paint.Cap.SQUARE);
    backgroundPaint.setColor(context.getResources().getColor(colorRes));
    backgroundPaint.setAntiAlias(true);
    backgroundPaint.setStrokeWidth(strokeWidth);
    backgroundPaint.setStyle(Paint.Style.STROKE);
}

public int getTotalSections() {
    return totalSections;
}

public void setTotalSections(int totalSections) {
    this.totalSections = totalSections;
    invalidate();
}

public int getFullSections() {
    return fullSections;
}

public void setNumberOfSections(int fullSections, int totalSections, int waiting) {
    this.fullSections = fullSections;
    this.totalSections = totalSections;
    this.waiting = waiting;
    invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    rect.set(getLeft() + PADDING, getTop() + PADDING, getRight() - PADDING, getBottom() - PADDING);
    float angleOfSection = (DEGREES_IN_CIRCLE / totalSections) - DIVIDER_ANGLE;
    // Drawing the inner ring
    for (int i = 0; i < totalSections; i++) {
        // -90 because it doesn't start at the top, so rotate by -90
        // divider_angle/2 especially in 2 sections, it's visibly rotated by Divider angle, so we split this between last and first
        float startAngle = -90 + i * (angleOfSection + DIVIDER_ANGLE) + DIVIDER_ANGLE / 2;
        if (i < fullSections) {
            canvas.drawArc(rect, startAngle, angleOfSection, false, paint);
        } else {
            canvas.drawArc(rect, startAngle, angleOfSection, false, backgroundPaint);
        }
    }
    // Drawing the outer ring
    rect.set(getLeft() + PADDING2, getTop() + PADDING2, getRight() - PADDING2, getBottom() - PADDING2);
    for (int i = 0; i < waiting; i++) {
        float startAngle = -90 + i * (angleOfSection + DIVIDER_ANGLE) + DIVIDER_ANGLE / 2;
        canvas.drawArc(rect, startAngle, angleOfSection, false, waitingPaint);
    }
}
}

Notice that this code won't give you the outer ring's 'empty' slots, since we decided against them in the end. The inner circle will have both the empty and filled slots. The whole class can be reused, and it's responsible just for the 2 rings that are drawn, the 6/6, +3 and the red circle are parts of another view.

最重要的代码是onDraw 方法。它包含在 for 循环中绘制圆弧的逻辑,以及计算角度和在角度之间添加空格的逻辑。一切都旋转了 -90 度,因为我需要它从顶部开始,而不是从右边开始,因为它是 Android 中的 0 度角。它并没有那么复杂,您可以根据需要对其进行修改以更好地满足您的需求。

关于Android:自定义圆形ProgressBar,中间有空格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34103722/

相关文章:

android - TextView setVisibility(View.GONE) 没有删除我的 CustomTextView

android - 图片未显示在推送通知中

java - Socket.io android java客户端接收消息和发送文件示例

Android 视频 MediaCodec 压缩速度慢

java - Android屏幕坐标到 Canvas View 坐标

android - 以编程方式绘制气泡

android - 测试自定义 View 的 onMeasure/onLayout/onDraw 方法的好方法是什么?

android - 如何更改 Lollipop 中的 DatePicker 日历 View 背景颜色?

android - 警告 : API 'variant.getJavaCompile()' is obsolete and has been replaced with 'variant.getJavaCompileProvider()'

java - 将简单的 html 渲染到 Canvas 上