如何使用 Android 画布绘制一个仅具有左上和右上圆角的矩形?

77

我找到了一个可以制作所有四个角都是圆形的矩形的函数,但我想只让顶部两个角是圆形的。我该怎么做?

canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, paint);

1
你不能只画一个圆角矩形,然后在底部半部分画一个普通矩形(用普通的矩形覆盖圆角部分)吗? - interstar
16个回答

5

绘制实心边框的一种简单有效的方法是使用裁剪 - 矩形裁剪基本上是免费的,比编写自定义路径需要更少的代码。

如果我想要一个顶部左侧和右侧圆角为50像素的300x300矩形,则可以执行以下操作:

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

这种方法只适用于对2或3个相邻角进行舍入,因此比基于Path的方法更少配置性,但是使用圆角矩形更有效率,因为drawRoundRect()完全由硬件加速(即被细分为三角形),而drawPath()总是回退到软件渲染(以软件方式绘制路径位图,并将其上传到GPU缓存中)。

对于小量稀疏绘制来说,并不是重大的性能问题,但是如果您正在动画化路径,则软件绘制的成本可能会使帧时间更长,并增加丢帧的几率。路径掩码还会占用内存。

如果您确实想采用基于Path的方法,我建议使用GradientDrawable来简化代码行数(假设您不需要设置自定义着色器,例如绘制位图)。

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

通过GradientDrawable#setCornerRadii(),您可以将任何角设置为任何圆角半径,并在状态之间合理地进行动画处理。


裁剪不是反锯齿的;在裁剪圆形物体时有问题。 - urSus

4
也许以下代码可以帮助你。
        Paint p = new Paint();
        p.setColor(color);

        float[] corners = new float[]{
                15, 15,        // Top, left in px
                15, 15,        // Top, right in px
                15, 15,          // Bottom, right in px
                15, 15           // Bottom,left in px
        };

        final Path path = new Path();
        path.addRoundRect(rect, corners, Path.Direction.CW);
        // Draw 
        canvas.drawPath(path, p);

4
这里是对上述问题的回答。我创建了一个Kotlin扩展函数,它使用Path以及quadTo函数,可以在更低级别的API中使用。
fun Canvas.drawRoundRectPath(
rectF: RectF,
radius: Float,
roundTopLeft: Boolean,
roundTopRight: Boolean,
roundBottomLeft: Boolean,
roundBottomRight: Boolean,
paint: Paint) {

val path = Path()

//Move path cursor to start point
if (roundBottomLeft) {
    path.moveTo(rectF.left, rectF.bottom - radius)
} else {
    path.moveTo(rectF.left, rectF.bottom)
}

// drawing line and rounding top left curve
if (roundTopLeft) {
    path.lineTo(rectF.left, rectF.top + radius)
    path.quadTo(rectF.left, rectF.top, rectF.left + radius, rectF.top)
} else {
    path.lineTo(rectF.left, rectF.top)
}

// drawing line an rounding top right curve
if (roundTopRight) {
    path.lineTo(rectF.right - radius, rectF.top)
    path.quadTo(rectF.right, rectF.top, rectF.right, rectF.top + radius)
} else {
    path.lineTo(rectF.right, rectF.top)
}

// drawing line an rounding bottom right curve
if (roundBottomRight) {
    path.lineTo(rectF.right, rectF.bottom - radius)
    path.quadTo(rectF.right, rectF.bottom, rectF.right - radius, rectF.bottom)
} else {
    path.lineTo(rectF.right, rectF.bottom)
}

// drawing line an rounding bottom left curve
if (roundBottomLeft) {
    path.lineTo(rectF.left + radius, rectF.bottom)
    path.quadTo(rectF.left, rectF.bottom, rectF.left, rectF.bottom - radius)
} else {
    path.lineTo(rectF.left, rectF.bottom)
}
path.close()

drawPath(path, paint)
}

我们可以使用画布对象调用该函数并传递RectF,该对象包含我们要应用曲线的尺寸。
另外,我们可以传递一个布尔值,以确定我们要圆角的哪些角。此答案还可以进一步定制,以接受单个角的半径。

如果我在自己编写代码之前就找到了这部分代码,那就太好了。哈哈! - Oleksandr.D

3
您可以使用Canvas中的drawLine()drawArc()函数逐个绘制该图形。

1
但是drawArc()方法是在API 21中引入的,是否有其他方法可以做同样的事情?例如画一个弧线? - Giridhar Karnik
自 API 1 以来,已经有另一个版本的 drawArc() 可用。 - JohnyTex

2

使用PaintDrawable可能更好:

    val topLeftRadius = 10
    val topRightRadius = 10
    val bottomLeftRadius = 0
    val bottomRightRadius = 0
    val rect = Rect(0, 0, 100, 100)
    val paintDrawable = PaintDrawable(Color.RED)
    val outter = floatArrayOf(topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
            bottomLeftRadius, bottomLeftRadius, bottomRightRadius, bottomRightRadius)
    paintDrawable.setCornerRadii(outter)
    paintDrawable.bounds = rect
    paintDrawable.draw(canvas)

1

使用左侧圆角绘制圆角矩形

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

这个方法并不为矩形提供圆角,它只为一些角提供了圆形,而不是全部,结果形状会变形。我想你需要再做一点工作。 - Bahadir Tasdemir
1
在onDraw方法中不应创建新对象 - 使用预分配的Path。 - Evgenii Vorobei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接