문제 설명
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:
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);
}
}
}