Подтвердить что ты не робот

Android: поиск метода drawArc() с внутренним и внешним радиусом

У меня есть следующий пользовательский вид:

alt text

Это я достиг с помощью метода Canvas 'drawArc(). Однако с помощью этого метода drawArc() я не могу ограничить внутренний радиус дуги.

Что бы я хотел, это примерно так:

alt text

где осталось только внешнее кольцо.

Мне нужна функция drawArc(), где я могу установить внутренний радиус дуги. Кто-нибудь знает, как это сделать?

(BTW, перекрашивание внутренней области не работает, потому что оно должно быть прозрачным. Покраска внутреннего круга с помощью Color.TRANSPARENT после окраски красных и синих конусов не удаляет старый цвет. Он просто кладет еще один слой сверху, прозрачный и через который я все еще вижу красный и синий)

4b9b3361

Ответ 1

Вы можете рисовать по внутренней области с помощью протокола PorterDuff xfermode под названием "Очистить". Это приведет к стиранию пикселей.

Ответ 2

Вы можете сделать это:

    Paint paint = new Paint();
    final RectF rect = new RectF();
    //Example values
    rect.set(mWidth/2- mRadius, mHeight/2 - mRadius, mWidth/2 + mRadius, mHeight/2 + mRadius); 
    paint.setColor(Color.GREEN);
    paint.setStrokeWidth(20);
    paint.setAntiAlias(true);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStyle(Paint.Style.STROKE);
    canvas.drawArc(rect, -90, 360, false, paint);

Ключ находится в paint.setStyle(Paint.Style.STROKE);, он обрезает центр дуги штрихом, который вы определяете в setStrokeWidth (в примере рисует дугу с радиусом mRadius и толщиной 20 пикселей).

Надеюсь, что это поможет!

Ответ 3

private static final float CIRCLE_LIMIT = 359.9999f;
/**
 * Draws a thick arc between the defined angles, see {@link Canvas#drawArc} for more.
 * This method is equivalent to
 * <pre><code>
 * float rMid = (rInn + rOut) / 2;
 * paint.setStyle(Style.STROKE); // there nothing to fill
 * paint.setStrokeWidth(rOut - rInn); // thickness
 * canvas.drawArc(new RectF(cx - rMid, cy - rMid, cx + rMid, cy + rMid), startAngle, sweepAngle, false, paint);
 * </code></pre>
 * but supports different fill and stroke paints.
 * 
 * @param canvas
 * @param cx horizontal middle point of the oval
 * @param cy vertical middle point of the oval
 * @param rInn inner radius of the arc segment
 * @param rOut outer radius of the arc segment
 * @param startAngle see {@link Canvas#drawArc}
 * @param sweepAngle see {@link Canvas#drawArc}, capped at &plusmn;360
 * @param fill filling paint, can be <code>null</code>
 * @param stroke stroke paint, can be <code>null</code>
 * @see Canvas#drawArc
 */
public static void drawArcSegment(Canvas canvas, float cx, float cy, float rInn, float rOut, float startAngle,
        float sweepAngle, Paint fill, Paint stroke) {
    if (sweepAngle > CIRCLE_LIMIT) {
        sweepAngle = CIRCLE_LIMIT;
    }
    if (sweepAngle < -CIRCLE_LIMIT) {
        sweepAngle = -CIRCLE_LIMIT;
    }

    RectF outerRect = new RectF(cx - rOut, cy - rOut, cx + rOut, cy + rOut);
    RectF innerRect = new RectF(cx - rInn, cy - rInn, cx + rInn, cy + rInn);

    Path segmentPath = new Path();
    double start = toRadians(startAngle);
    segmentPath.moveTo((float)(cx + rInn * cos(start)), (float)(cy + rInn * sin(start)));
    segmentPath.lineTo((float)(cx + rOut * cos(start)), (float)(cy + rOut * sin(start)));
    segmentPath.arcTo(outerRect, startAngle, sweepAngle);
    double end = toRadians(startAngle + sweepAngle);
    segmentPath.lineTo((float)(cx + rInn * cos(end)), (float)(cy + rInn * sin(end)));
    segmentPath.arcTo(innerRect, startAngle + sweepAngle, -sweepAngle);
    if (fill != null) {
        canvas.drawPath(segmentPath, fill);
    }
    if (stroke != null) {
        canvas.drawPath(segmentPath, stroke);
    }
}

Может быть расширен до овальной дуги путем дублирования rInn и rOut для направлений x и y.

Также не был частью вопроса, но нарисовать текст в середине сегмента:

textPaint.setTextAlign(Align.CENTER);
Path midway = new Path();
float r = (rIn + rOut) / 2;
RectF segment = new RectF(cx - r, cy - r, cx + r, cy + r);
midway.addArc(segment, startAngle, sweepAngle);
canvas.drawTextOnPath("label", midway, 0, 0, textPaint);

Ответ 4

Вы можете попробовать выполнить ShapeDrawable

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape android:shape="oval" >
        <size
            android:height="56dp"
            android:width="56dp" />

        <stroke
            android:width="10dp"
            android:color="#0000ff" />
    </shape>
</item>
<item>
    <shape android:shape="oval" >
        <size
            android:height="24dp"
            android:width="25dp" />

        <stroke
            android:dashGap="10dp"
            android:dashWidth="10dp"
            android:width="10dp"
            android:color="#FF0000" />
    </shape>
</item>