Как нарисовать треугольник с закругленным углом на андроидном холсте? [Дубликат]

SELECT column FROM
( SELECT column, dbms_random.value FROM table ORDER BY 2 )
where rownum <= 20;
35
задан peer 16 October 2016 в 09:21
поделиться

9 ответов

Вы можете нарисовать эту часть по частям с помощью функций drawLine() и drawArc() из Canvas.

3
ответ дан Zelimir 15 August 2018 в 21:04
поделиться
  • 1
    Кусок кода будет оценен – Asterius 21 May 2015 в 14:50
  • 2
    Но метод drawArc () был введен в API 21, есть ли другой метод, где я могу сделать то же самое? Как нарисовать дугу? – Giridhar Karnik 23 June 2015 в 14:20

Я достиг этого, выполнив следующие шаги.

Это предпосылки для того, чтобы округленный прямоугольник выглядел аккуратным

  • Радиус ребер должен быть равный (высота прямоугольника / 2). Это связано с тем, что если его любое другое значение, то место, где кривая встречает прямую линию прямоугольника, не будет

Далее следуют шаги рисования округленного прямоугольника.

  • Сначала мы рисуем 2 круга с левой и правой стороны, с радиусом = высота прямоугольника / 2
  • . Затем мы рисуем прямоугольник между этими кругами, чтобы получить желаемый округленный прямоугольник.

Я отправляю код ниже

private void drawRoundedRect(Canvas canvas, float left, float top, float right, float bottom) {
    float radius = getHeight() / 2;
    canvas.drawCircle(radius, radius, radius, mainPaint);
    canvas.drawCircle(right - radius, radius, radius, mainPaint);
    canvas.drawRect(left + radius, top, right - radius, bottom, mainPaint);
}

Теперь это приводит к действительно хорошему округленному прямоугольнику, подобному показанному ниже

1
ответ дан Bhargav 15 August 2018 в 21:04
поделиться

Один простой и эффективный способ нарисовать сплошную сторону - использовать отсечение - прямое обрезание, по сути, бесплатное, и гораздо меньше кода для записи, чем пользовательский путь.

Если я хочу прямоугольник 300x300, с верхним левым и правым закругленными на 50 пикселей, вы можете сделать:

canvas.save();
canvas.clipRect(0, 0, 300, 300);
canvas.drawRoundRect(new RectF(0, 0, 300, 350), 50, 50, paint);
canvas.restore();

Этот подход будет работать только для округления на 2 или 3 смежных углах, поэтому он немного менее настраивается, чем подход на основе Path , но использование round rects более эффективно, поскольку drawRoundRect () полностью аппаратно ускорено (т. е. тесселлировано в треугольники), в то время как drawPath () всегда возвращается к рендерингу программного обеспечения (программное обеспечение - рисовать растровое изображение пути и загружать его для кэширования GPU).

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

Если вы хотите перейти с помощью подхода на основе Path, я бы рекомендовал использовать GradientDrawable для упрощения строк кода (при условии, что вам не нужно настраивать пользовательские настройки shader, например, для рисования растрового изображения).

mGradient.setBounds(0, 0, 300, 300);
mGradient.setCornerRadii(new int[] {50,50, 50,50, 0,0, 0,0});

С помощью GradientDrawable # setCornerRadii () вы можете установить любой угол в любую округленность и разумно анимировать между состояниями.

1
ответ дан Chris Craik 15 August 2018 в 21:04
поделиться

Я изменил ответ , чтобы вы могли указать, в каком углу вы хотите быть круглым, и какой из них вы хотите быть резким. также работает на pre-lolipop

Пример использования :

только верхний правый и углы botton-right закруглены

 Path path = RoundedRect(0, 0, fwidth , fheight , 5,5,
                     false, true, true, false);
 canvas.drawPath(path,myPaint);

RoundRect:

    public static Path RoundedRect(
            float left, float top, float right, float bottom, float rx, float ry,
               boolean tl, boolean tr, boolean br, boolean bl
    ){
        Path path = new Path();
        if (rx < 0) rx = 0;
        if (ry < 0) ry = 0;
        float width = right - left;
        float height = bottom - top;
        if (rx > width / 2) rx = width / 2;
        if (ry > height / 2) ry = height / 2;
        float widthMinusCorners = (width - (2 * rx));
        float heightMinusCorners = (height - (2 * ry));

        path.moveTo(right, top + ry);
        if (tr)
            path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
        else{
            path.rLineTo(0, -ry);
            path.rLineTo(-rx,0);
        }
        path.rLineTo(-widthMinusCorners, 0);
        if (tl)
            path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
        else{
            path.rLineTo(-rx, 0);
            path.rLineTo(0,ry);
        }
        path.rLineTo(0, heightMinusCorners);

        if (bl)
            path.rQuadTo(0, ry, rx, ry);//bottom-left corner
        else{
            path.rLineTo(0, ry);
            path.rLineTo(rx,0);
        }

        path.rLineTo(widthMinusCorners, 0);
        if (br)
            path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
        else{
            path.rLineTo(rx,0);
            path.rLineTo(0, -ry);
        }

        path.rLineTo(0, -heightMinusCorners);

        path.close();//Given close, last lineto can be removed.

        return path;
    }
19
ответ дан Community 15 August 2018 в 21:04
поделиться
  • 1
    Вы должны исправить мой мой ответ там с подходящей дугой безье, аппроксимирующей углы. spencermortensen.com/articles/bezier-circle И конвертировать использование побитовой вещи стиля C-стиля для углов, а не пучка булевых. static final int SHARP_TOP_RIGHT = 0b0001, статический окончательный int SHARP_TOP_LEFT = 0b0010; - тогда вы можете назвать его, getRoundRect (0, 0, fwidth, fheight, 5, 5, SHARP_TOP_LEFT | SHARP_BOTTOM_LEFT); с ifs being (if ((SHARP_TOP_LEFT & amp; cornerflag) == 0) ...; также вспомогательная функция, которая, если ее пропустить, вызывает ее с 0. Таким образом RoundRect (l, tl, r, b, rx, ry) отлично работает Все статические окончательные. – Tatarize 17 April 2016 в 07:39
  • 2
    Отлично! Это то, что я искал! Спасибо дружище! – Adnan 9 June 2016 в 06:07

Я бы нарисовал два прямоугольника:

canvas.drawRect(new RectF(0, 110, 100, 290), paint);
canvas.drawRoundRect(new RectF(0, 100, 100, 200), 6, 6, paint);

Или что-то в этом роде, вы просто перекрываете их, чтобы верхние углы были круглыми. Предпочтительно вы должны написать метод для этого

38
ответ дан Durza007 15 August 2018 в 21:04
поделиться
  • 1
    Что мне нужно, чтобы установить альфу с целым прямоугольником, секция перекрытия будет иметь различное альфа-значение с другими – virsir 5 May 2011 в 13:13
  • 2
    требуется уровень api & gt; = 21 – V. Kalyuzhnyu 28 February 2016 в 06:24
  • 3
    @ В.Калюжню, используемая в ответе с использованием метода, доступна с API 1, вы должны говорить о drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint), который доступен из API 21. – もっくん 1 May 2017 в 08:26

провести круглый прямоугольник с закругленными углами слева

  private void drawRoundRect(float left, float top, float right, float bottom, Paint paint, Canvas canvas) {
        Path path = new Path();
        path.moveTo(left, top);
        path.lineTo(right, top);
        path.lineTo(right, bottom);
        path.lineTo(left + radius, bottom);
        path.quadTo(left, bottom, left, bottom - radius);
        path.lineTo(left, top + radius);
        path.quadTo(left, top, left + radius, top);
        canvas.drawPath(path, onlinePaint);
    }
1
ответ дан georgehardcore 15 August 2018 в 21:04
поделиться
  • 1
    Этот метод не обеспечивает округлые углы для прямоугольника, он обеспечивает округлые формы для некоторых углов, но не для всех, форма результата искажается. Думаю, вы должны немного поработать над этим. – Bahadir Tasdemir 2 September 2015 в 06:43
public static Path composeRoundedRectPath(RectF rect, float topLeftDiameter, float topRightDiameter,float bottomRightDiameter, float bottomLeftDiameter){
    Path path = new Path();
    topLeftDiameter = topLeftDiameter < 0 ? 0 : topLeftDiameter;
    topRightDiameter = topRightDiameter < 0 ? 0 : topRightDiameter;
    bottomLeftDiameter = bottomLeftDiameter < 0 ? 0 : bottomLeftDiameter;
    bottomRightDiameter = bottomRightDiameter < 0 ? 0 : bottomRightDiameter;

    path.moveTo(rect.left + topLeftDiameter/2 ,rect.top);
    path.lineTo(rect.right - topRightDiameter/2,rect.top);
    path.quadTo(rect.right, rect.top, rect.right, rect.top + topRightDiameter/2);
    path.lineTo(rect.right ,rect.bottom - bottomRightDiameter/2);
    path.quadTo(rect.right ,rect.bottom, rect.right - bottomRightDiameter/2, rect.bottom);
    path.lineTo(rect.left + bottomLeftDiameter/2,rect.bottom);
    path.quadTo(rect.left,rect.bottom,rect.left, rect.bottom - bottomLeftDiameter/2);
    path.lineTo(rect.left,rect.top + topLeftDiameter/2);
    path.quadTo(rect.left,rect.top, rect.left + topLeftDiameter/2, rect.top);
    path.close();

    return path;
}
5
ответ дан Kvant 15 August 2018 в 21:04
поделиться
  • 1
    Спасибо за код, это сработало для меня. Но в коде есть небольшая ошибка: вы работаете с половиной требуемого радиуса - я полагаю, вы принимаете радиус как диаметр, но радиус уже вдвое меньше диаметра, поэтому вам следует сбросить все / 2 в код. – Ridcully 10 December 2016 в 18:41
  • 2
    Ridcully Dec вы правы, спасибо. – Kvant 15 December 2016 в 08:52

Использовать путь. Это имеет преимущество, заключающееся в том, что он работает для API менее 21 (поэтому Arc также ограничен, поэтому I quad). Это проблема, потому что не все имеют Lollipop. Однако вы можете указать RectF и установить значения с ним и использовать arc обратно в API 1, но тогда вы не сможете использовать статический (без объявления нового объекта для сборки объекта).

Рисование закругленного прямоугольника:

    path.moveTo(right, top + ry);
    path.rQuadTo(0, -ry, -rx, -ry);
    path.rLineTo(-(width - (2 * rx)), 0);
    path.rQuadTo(-rx, 0, -rx, ry);
    path.rLineTo(0, (height - (2 * ry)));
    path.rQuadTo(0, ry, rx, ry);
    path.rLineTo((width - (2 * rx)), 0);
    path.rQuadTo(rx, 0, rx, -ry);
    path.rLineTo(0, -(height - (2 * ry)));
    path.close();

В качестве полной функции:

static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) {
    Path path = new Path();
    if (rx < 0) rx = 0;
    if (ry < 0) ry = 0;
    float width = right - left;
    float height = bottom - top;
    if (rx > width/2) rx = width/2;
    if (ry > height/2) ry = height/2;
    float widthMinusCorners = (width - (2 * rx));
    float heightMinusCorners = (height - (2 * ry));

    path.moveTo(right, top + ry);
    path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
    path.rLineTo(-widthMinusCorners, 0);
    path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
    path.rLineTo(0, heightMinusCorners);

    if (conformToOriginalPost) {
        path.rLineTo(0, ry);
        path.rLineTo(width, 0);
        path.rLineTo(0, -ry);
    }
    else {
        path.rQuadTo(0, ry, rx, ry);//bottom-left corner
        path.rLineTo(widthMinusCorners, 0);
        path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
    }

    path.rLineTo(0, -heightMinusCorners);

    path.close();//Given close, last lineto can be removed.

    return path;
}

Вы хотите полностью привязать эти угловые биты, а не квадраты по ним. Это то, что подходит для соответствия TOOriginalPost. Просто подключитесь к контрольной точке.

Если вы хотите сделать это, но не заботитесь о материалах, предшествующих Lollipop, и настоятельно настаивайте на том, что если ваши rx и ry достаточно высоки, он должен нарисовать круг.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) {
    Path path = new Path();
    if (rx < 0) rx = 0;
    if (ry < 0) ry = 0;
    float width = right - left;
    float height = bottom - top;
    if (rx > width/2) rx = width/2;
    if (ry > height/2) ry = height/2;
    float widthMinusCorners = (width - (2 * rx));
    float heightMinusCorners = (height - (2 * ry));

    path.moveTo(right, top + ry);
    path.arcTo(right - 2*rx, top, right, top + 2*ry, 0, -90, false); //top-right-corner
    path.rLineTo(-widthMinusCorners, 0);
    path.arcTo(left, top, left + 2*rx, top + 2*ry, 270, -90, false);//top-left corner.
    path.rLineTo(0, heightMinusCorners);
    if (conformToOriginalPost) {
        path.rLineTo(0, ry);
        path.rLineTo(width, 0);
        path.rLineTo(0, -ry);
    }
    else {
        path.arcTo(left, bottom - 2 * ry, left + 2 * rx, bottom, 180, -90, false); //bottom-left corner
        path.rLineTo(widthMinusCorners, 0);
        path.arcTo(right - 2 * rx, bottom - 2 * ry, right, bottom, 90, -90, false); //bottom-right corner
    }

    path.rLineTo(0, -heightMinusCorners);

    path.close();//Given close, last lineto can be removed.
    return path;
}

Итак, concToOriginalPost на самом деле рисует закругленный прямоугольник без двух нижних битов.

34
ответ дан Tatarize 15 August 2018 в 21:04
поделиться
  • 1
    По-моему, я считаю, что относительные функции пути намного лучше, потому что вам нужно только беспокоиться о том, на какой путь будет нарисован путь. – TheRealChx101 21 October 2015 в 09:59
  • 2
    @ chx101 да, хорошо, отредактировал его как относительный и начал на кривой, поэтому close () может покрыть lineto. – Tatarize 22 October 2015 в 20:08
  • 3
    @Tatrize Вау, ты переписал все это? – TheRealChx101 23 October 2015 в 04:25
  • 4
    Там есть часть оригинального ответа. Я в основном в основном отказался от исходного кода и фактически полностью предоставил фактический запрошенный ответ. Но это было больше, потому что дуги были грубыми, и поэтому мне пришлось отменить направление, а затем переупорядочить их, чтобы положить последние два внизу, чтобы они были легко удалены. Затем я проверил W3 Rect для типичной стандартной реализации того, что делать для различных значений RX, RY (выбрано значение 0, если отрицательное, а не ошибка). w3.org/TR/SVG/shapes.html#RectElement – Tatarize 23 October 2015 в 05:18
  • 5
    И мне приходит в голову, что даже без дуги окружности можно сделать гораздо более круговую кривую с квадратичной безье, а не с квадом. А именно, вы будете контролировать контрольные точки в точках 1, c и c, 1 (по отношению к квадранту), где C = (4/3) * tan (pi / 8) или сделать спенсер-mortensen немного улучшенным значением для C. Квадрат с контрольной точкой в ​​углу работает, но на самом деле немного наивно. – Tatarize 3 January 2016 в 09:31

Простая вспомогательная функция, записанная в Kotlin.

private fun Canvas.drawTopRoundRect(rect: RectF, paint: Paint, radius: Float) {
    // Step 1. Draw rect with rounded corners.
    drawRoundRect(rect, radius, radius, paint)

    // Step 2. Draw simple rect with reduced height,
    // so it wont cover top rounded corners.
    drawRect(
            rect.left,
            rect.top + radius,
            rect.right,
            rect.bottom,
            paint
    )
}

Использование:

canvas.drawTopRoundRect(rect, paint, radius)
7
ответ дан Vadim Akhmerov 15 August 2018 в 21:04
поделиться
  • 1
    он будет перекрываться, а цвет альфа будет отличаться – Jemshit Iskenderov 10 April 2018 в 12:24
Другие вопросы по тегам:

Похожие вопросы: