1

How to draw a generic shape with Jetpack compose?

I want to draw roundedCornerCircle but the right side should have an inside curve instead of an outside curve.

I tried to give a negative radius in roundedCornerShape but it is not working. Can someone help me to understand how to customize this and draw this in Android Jetpack compose?

Ignore this rectangle in middle. enter image description here

Pranav P
  • 1,755
  • 19
  • 39

2 Answers2

3

Result

enter image description here

If you want this as a Shape to be clickable inside boundaries of this custom shape you can create a RoundedRectangle with corner on left side only using

val shape = GenericShape { size: Size, layoutDirection: LayoutDirection ->
    val width = size.width
    val height = size.height

    addArc(
        oval = Rect(
            offset = Offset.Zero,
            size = Size(height, height)
        ),
        startAngleDegrees = 90f,
        sweepAngleDegrees = 180f,
    )
    lineTo(width, 0f)
    lineTo(width, height)
    lineTo(height, height)

}

Then to clip right side you can use BlendMode as in this q&a

How to clip or cut a Composable?

Box(
    modifier = Modifier
        .size(200.dp, 100.dp)
        .clip(shape)
        .drawWithContent {

            val width = size.width
            val height = size.height
            val radius = 30f


            with(drawContext.canvas.nativeCanvas) {
                val checkPoint = saveLayer(null, null)
                // Destination
                drawContent()

                // Source
                drawArc(
                    color = Color.Transparent,
                    startAngle = 90f,
                    sweepAngle = 180f,
                    topLeft = Offset(
                        width - radius, 0f
                    ),
                    size = Size(2 * radius, height),
                    useCenter = false,
                    blendMode = BlendMode.SrcOut
                )
                restoreToCount(checkPoint)
            }
        }
        .background(Yellow400)
        .clickable {

        }
)

Full implementation

@Preview
@Composable
fun ShapePreview() {

    Column(modifier = Modifier
        .fillMaxSize()
        .padding(20.dp)) {
val shape = GenericShape { size: Size, layoutDirection: LayoutDirection ->
    val width = size.width
    val height = size.height

    addArc(
        oval = Rect(
            offset = Offset.Zero,
            size = Size(height, height)
        ),
        startAngleDegrees = 90f,
        sweepAngleDegrees = 180f,
    )
    lineTo(width, 0f)
    lineTo(width, height)
    lineTo(height, height)

}

        Box(
            modifier = Modifier
                .size(200.dp, 100.dp)
                .clip(shape)
                .drawWithContent {

                    val width = size.width
                    val height = size.height
                    // Change this as required, ra
                    val radius = 80f


                    with(drawContext.canvas.nativeCanvas) {
                        val checkPoint = saveLayer(null, null)
                        // Destination
                        drawContent()

                        // Source
                        drawArc(
                            color = Color.Transparent,
                            startAngle = 90f,
                            sweepAngle = 180f,
                            topLeft = Offset(
                                width - radius, 0f
                            ),
                            size = Size(2 * radius, height),
                            useCenter = false,
                            blendMode = BlendMode.SrcOut
                        )
                        restoreToCount(checkPoint)
                    }
                }
                .background(Orange400)
                .clickable {

                }
        )
    }
}

If you only need to draw it in DrawScope you don't need the Shape at all. Create a RoundedRect with left rounded side and do blend mode for the right side.

Thracian
  • 43,021
  • 16
  • 133
  • 222
1

To create a custom shape, you can:

a) create a custom class by implementing the Shape interface and overriding its createOutline function or

b) use GenericShape and pass a builder lambda to it. Under the hood, GenericShape overrides the createOutline function of Shape .

Arda Kazancı
  • 8,341
  • 4
  • 28
  • 50