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

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

альтернативный текст

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

Я хотел бы иметь что-то вроде этого:

альтернативный текст

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

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

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


person znq    schedule 06.10.2010    source источник
comment
Можете ли вы опубликовать свой последний код после получения вашего окончательного требования? Спасибо   -  person anddev    schedule 09.02.2012
comment
Кто-нибудь знает, как сделать гладкие края углов встречи, т.к. в моем случае, когда я делаю кольцо с 4-5 одинаковыми распределениями и разными цветами, я вижу фон по краям   -  person Akhil Dad    schedule 14.10.2014


Ответы (5)


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

person Romain Guy    schedule 06.10.2010
comment
Это возможное решение. Но что делать в случае, если во внутреннем круге уже что-то нарисовано, что я не хочу ни закрашивать, ни стирать пиксели и перерисовывать? - person znq; 06.10.2010
comment
Нарисуйте круг на закадровом растровом изображении ARGB8888, сделайте там очистку, затем нарисуйте растровое изображение на холсте. Таким образом, вам также не придется каждый раз перерисовывать круг. - person Romain Guy; 07.10.2010
comment
Итак, изучив, как на самом деле это сделать, я немного растерялся: является ли растровое изображение ARGB8888 обычным растровым изображением goo.gl /ygTn — и как получить те же функции рисования, что и в Canvas? - person znq; 07.10.2010
comment
Обновление: я понял, что на самом деле могу сделать это таким образом. Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Холст c = новый холст (bm); а затем рисовать на холсте, который затем записывает фактические пиксели в растровое изображение. - person znq; 07.10.2010

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

    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 и толщиной 20px).

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

person Racker    schedule 01.04.2011
comment
Работает как шарм! Иногда я забываю вычесть обводку из контейнера и получаю обрезанный круг. Спасибо. - person Tom; 12.06.2012
comment
И если вы используете paint.setStrokeCap(Paint.Cap.BUTT); вместо paint.setStrokeCap(Paint.Cap.ROUND);, вы получите именно то, что нужно в вопросе. - person PhoneixS; 02.07.2013
comment
Думаю можно смело использовать canvas.drawArc(rect,0,360,false,paint); вместо -90 - person Gerard; 31.10.2013
comment
Можете ли вы установить цвет градиента (например, шейдер) для этого? - person Snake; 08.01.2015
comment
Paint.Cap.BUTT используется по умолчанию, поэтому вы можете просто удалить строку paint.setStrokeCap();. - person Vitor Hugo Schwaab; 19.09.2018

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's 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);
person TWiStErRob    schedule 10.08.2014
comment
этот код потрясающий! Однако у меня есть вопрос, есть ли способ сделать линии между кругами другого цвета, чем цвет периметра кругов? - person Snake; 08.01.2015
comment
@Snake, тебе придется разделить вызовы segmentPath.*To() на несколько вызовов Path и нарисовать каждый отдельно с помощью выбранных цветов обводки. Вы можете делать то, что вы описываете, с двумя путями: moveTo,lineTo,moveTo,lineTo и moveTo,arcTo,moveTo,arcTo. Вам все равно придется сохранить текущий, чтобы было что заполнить. - person TWiStErRob; 09.01.2015
comment
Я думаю, что я смутно понял это. Поскольку мне все еще нужна ваша помощь, я создал еще один вопрос, как вы предложили. Ждем вашей помощи. Вот ссылка stackoverflow.com/questions/27850634/ - person Snake; 09.01.2015
comment
Не обязательно использовать lineTo. Для второго arcTo() добавьте false в качестве последнего параметра; это нарисует линию от конца первой дуги до начала второй. Затем close() путь. - person John Perry; 07.06.2017

рисование круга и дуги. следующий код немного грязный, но может помочь

        int sweepAngle sweepAngle = (360/7)%360;
    int startAngle = -90;
    int x = getWidth()/2;
    int y = getHeight()/2;
    int radius;
    radius = getWidth()/2-50;
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(50);
    paint.setColor(Color.WHITE);

    paint.setColor(Color.parseColor("#CD5C5C"));
    mBarPaintFill.setAntiAlias(true);

    canvas.drawCircle(x , y , radius, paint);
    paint.setColor(Color.BLUE);
    for (int i = 1 ; i<=5 ; i++){

        canvas.drawArc(x-radius,y-radius,x+radius,y+radius,startAngle,sweepAngle,false,paint);
        startAngle = (startAngle + sweepAngle+20)%360;
    }

введите здесь описание изображения

person Irfan Ul Haq    schedule 25.02.2019

Вы можете попробовать следовать 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>

person shailesh    schedule 07.04.2015