Search code examples
androidkotlincanvasandroid-jetpack-composerounded-corners

How to draw rounded corner polygons in Jetpack Compose Canvas?


I'm trying to create a rounded triangle using Canvas in Jetpack Compose.

I try this code for drawing triangle:

@Composable
fun RoundedTriangle() {
    Canvas(modifier = Modifier.size(500.dp)) {
        val trianglePath = Path().apply {
            val height = size.height
            val width = size.width
            moveTo(width / 2.0f, 0f)
            lineTo(width, height)
            lineTo(0f, height)
        }
            drawPath(trianglePath, color = Color.Blue)
    }
}

But I don't know how to round the triangle corners. I also tried to use arcTo, but I was unable to get a suitable result.

How can I draw something like the figure below?

enter image description here


Solution

  • For Stroke you can specify rounding like this:

    drawPath(
        ...
        style = Stroke(
            width = 2.dp.toPx(),
            pathEffect = PathEffect.cornerPathEffect(4.dp.toPx())
        )
    )
    

    Yet Fill seems lack of support rounding. I've created a feature request, please star it.

    But Canvas has drawOutline function, which accepts both Outline, which can wrap a Path, and Paint, for which you can specify pathEffect:

    Canvas(modifier = Modifier.fillMaxWidth().aspectRatio(1f)) {
        val rect = Rect(Offset.Zero, size)
        val trianglePath = Path().apply {
            moveTo(rect.topCenter)
            lineTo(rect.bottomRight)
            lineTo(rect.bottomLeft)
            close()
        }
    
        drawIntoCanvas { canvas ->
            canvas.drawOutline(
                outline = Outline.Generic(trianglePath),
                paint = Paint().apply {
                    color = Color.Black
                    pathEffect = PathEffect.cornerPathEffect(rect.maxDimension / 3)
                }
            )
        }
    }
    

    Path helpers:

    fun Path.moveTo(offset: Offset) = moveTo(offset.x, offset.y)
    fun Path.lineTo(offset: Offset) = lineTo(offset.x, offset.y)
    

    Result: