Search code examples
androidandroid-jetpack-compose

creating a rounded bottom border on a card


I am trying to create a border at the bottom of a card using jetpack compose.

Kind of like this in order to make the card feel like it has a thickness to it.

border bottom

I did manage to get that working using two cards "stacked" on top of eachother

    Box(modifier = Modifier
        .wrapContentSize()
        .padding(5.dp)
        .padding(25.dp)
        .padding(0.dp,0.dp,0.dp,15.dp)) {

        Card(
            modifier = Modifier
                .size(180.dp, 200.dp)
                .offset(10.dp, 12.dp),
            elevation = CardDefaults.cardElevation(
                defaultElevation = 10.dp
            )
        ) {
        }
        Card(
            modifier = Modifier
                .size(180.dp, 200.dp)
                .offset(10.dp, 10.dp),
            elevation = CardDefaults.cardElevation(
                defaultElevation = 10.dp
            )
        ) {
        }
    }

But to me this feels like a pretty hacky solution and something I would like to avoid. So I wonder if there is any other ways of creating a similar effect?


Solution

  • You could try and experiment with drawBehind modifier. Stacking of rounded rects is involved too, but it looks much cleaner to me.

    Snippet below produces the following result:

    Card with thickness

    When you uncomment the line with semi-transparent backgroundColor, you can see what is being drawn behind the Card (it is full rounded rect, as you cannot set corners individually on Canvas with this method):

    Card with transparent background

    @Preview
    @Composable
    fun CardWithThickness(modifier: Modifier = Modifier) {
        val cardHeightDp = 100.dp
        val cornerRadiusDp = 20.dp
        val borderThicknessDp = 2.dp
        Box(
            modifier = Modifier.padding(bottom = borderThicknessDp)
        ) {
            Card(
                // backgroundColor = Color(0x99999999),
                shape = RoundedCornerShape(size = cornerRadiusDp),
                modifier = Modifier
                    .size(180.dp, cardHeightDp)
                    .drawBehind {
                        drawRoundRect(
                            color = Color.Red,
                            topLeft = Offset(0f, (cardHeightDp - 2 * cornerRadiusDp).toPx()),
                            size = this.size.copy(height = (2 * cornerRadiusDp + borderThicknessDp).toPx()),
                            cornerRadius = CornerRadius(cornerRadiusDp.toPx())
                        )
                    },
            ) {
                // ...
            }
        }
    }