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?
Result
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.