https://kotlinlang.org logo
Title
d

Deepak Gahlot

04/24/2023, 6:43 AM
Hello All, Please help in build this custom shape. I have been trying with Generic Shapes but unable to get the desired result.
o

Oleksandr Balan

04/24/2023, 11:18 AM
I would say the easiest way would be to combine 2 paths with union operation. I have created something called
ChatMessageBox
which adds a border with that shape.
@Composable
fun ChatMessageBox(
    modifier: Modifier = Modifier,
    triangleSize: Dp = 10.dp,
    cornerRadius: Dp = 8.dp,
    content: @Composable BoxScope.() -> Unit,
) {
    // Convert to DP to PX, because Path API works with pixels
    val triangleSizePx = LocalDensity.current.run { triangleSize.toPx() }
    val cornerRadiusPx = LocalDensity.current.run { cornerRadius.toPx() }

    val shape = remember(triangleSize, cornerRadius) {
        // Create a final shape as a GenericShape and build a path with a lambda
        GenericShape { size, _ ->
            // Create the first path with a triangle shape
            val p1 = Path().apply {
                val offset = size.center.y
                moveTo(0f, offset)
                lineTo(offset, 0f,)
                lineTo(offset, size.height)
                close()
            }
            // Create the second path with a rectangle with rounded corners, shifted by the triangle size
            val p2 = Path().apply {
                val rect = Rect(Offset(triangleSizePx, 0f), Offset(size.width, size.height))
                addRoundRect(RoundRect(rect, cornerRadiusPx, cornerRadiusPx))
            }
            // Combine two paths with union
            val path = Path().apply { op(p1, p2, PathOperation.Union) }
            // Add the final path to the shape
            addPath(path)
        }
    }

    // Shift a box content with start padding *after* border to compensate triangle size
    Box(
        modifier = modifier
            .border(1.dp, Color.Gray, shape)
            .padding(start = triangleSize),
        content = content
    )
}
In preview it could look like this. You could tweak triangle size and corners radius in
ChatMessageBox
composable.
@Preview(widthDp = 150)
@Composable
fun ChatMessageBoxPreview() {
    ChatMessageBox {
        Column(Modifier.padding(8.dp)) {
            Text("Item1")
            Row(Modifier.fillMaxWidth()) {
                Text("Item2", Modifier.weight(1f))
                Text("Item3", Modifier.weight(1f))
            }
        }
    }
}
d

Deepak Gahlot

04/24/2023, 12:23 PM
Thanks. Got it