Android: 사이에 공백이 있는 맞춤 원 ProgressBar (Android: Custom circle ProgressBar with spaces in between)


문제 설명

Android: 사이에 공백이 있는 맞춤 원 ProgressBar (Android: Custom circle ProgressBar with spaces in between)

서클이 있는 사용자 정의 보기를 만들려고 하는데 아래 이미지와 같이 런타임에 섹션이 있어야 합니다. onDraw 메서드에서 많은 것을 시도했지만 운이 없었습니다. https://github.com/donvigo/CustomProgressControls도 시도했습니다. 기본적으로 여러 섹션을 제공하고 각 섹션에서 필요에 따라 색상을 선택할 수 있습니다.

여기에 이미지 설명 입력

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));
} 

참조 솔루션

방법 1:

I might be a little late to the party, but I actually wrote a custom component that has 2 rings that look quite similar to what you're trying to achieve. You can just remove the outer ring easily. The image of what I got in the end:

enter image description here

Here's the class:

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.

The most important piece of the code is the onDraw method. It contains the logic for drawing the arcs in the for loop, as well as the logic for calculating the angles and adding spaces between them. Everything is rotated by ‑90 degrees, because I needed it to start at the top, rather than on the right, as it is the 0‑degree angle in Android. It's not that complex, and you can modify it to fit your needs better should you need to.

방법 2:

I find it easier to do math for drawArc(operating on angle values based on number of sections) rather than computing the arc length. Here's a quick idea, with a lot of hard‑coded properties, but you should be able to get the idea:

public class MyStrokeCircleView extends View {
    private Paint mPaint;
    private RectF mRect;
    private int mPadding;

    private int mSections;
    private int mFullArcSliceLength;
    private int mColorArcLineLength;
    private int mArcSectionGap;

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

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

    public MyStrokeCircleView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {
        mPaint = new Paint();
        mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(10);
        mPaint.setColor(ContextCompat.getColor(getContext(), android.R.color.darker_gray));

        mPadding = 5;
        mRect = new RectF(mPadding, mPadding, mPadding, mPadding);

        mSections = 4;
        mFullArcSliceLength = 360 / mSections;
        mArcSectionGap = mFullArcSliceLength / 10;
        mColorArcLineLength = mFullArcSliceLength ‑ 2 * mArcSectionGap;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mRect.right = getWidth() ‑ mPadding;
        mRect.bottom = getHeight() ‑ mPadding;
    }

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

        for (int i = 0; i < mSections; i++) {
            canvas.drawArc(mRect, i * mFullArcSliceLength + mArcSectionGap, mColorArcLineLength, false, mPaint);
        }
    }
}

(by nickVuckoN.T.)

참조 문서

  1. Android: Custom circle ProgressBar with spaces in between (CC BY‑SA 2.5/3.0/4.0)

#android-progressbar #ondraw #android-custom-view #android-canvas #Android






관련 질문

목록 보기 항목의 보기는 화면에서 보기를 스크롤한 후 원래 상태로 돌아갑니다. (listview item's view returns to original state after scroll the view off the screen)

Android의 비동기 클래스에서 FTP 다운로드에 진행률 표시줄을 표시하는 방법은 무엇입니까? (How to show the progress bar in FTP download in async class in Android?)

Android에서 진행률 표시줄의 ListView (ListView of Progress Bars in android)

안드로이드에서 24시간 SeekBar 또는 ProgressBar를 만드는 방법 (How to create 24hour SeekBar or ProgressBar in android)

Android: ProgressBar가 활동에서 이상하게 보입니다. (Android: ProgressBar looks strange in activity)

Android에서 기본 ProgressDialog 원 색상을 변경하는 방법 (How to change default ProgressDialog circle color in android)

Android: 사이에 공백이 있는 맞춤 원 ProgressBar (Android: Custom circle ProgressBar with spaces in between)

정적 수평 진행률 표시줄 Android (Static horizontal progress bar android)

Android progressBar setVisibility()가 작동하지 않음 (Android progressBar setVisibility() not working)

비동기 작업의 게시 진행률 (Publishing progress in async task)

BaseActvity/BaseFragment의 ProgressBar 관리 (ProgressBar management in BaseActvity/BaseFragment)

진행 중인 경고 대화 상자가 닫히거나 취소되지 않음 (Alertdialog running ongoing dosen't dismiss or cancel)







코멘트