You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose如何实现指定轮廓的自定义卡片形状?

如何在Jetpack Compose中实现带自定义右上角内凹的卡片形状?

你的核心问题是自定义GenericShape的路径逻辑有误,导致右上角的内凹曲线与目标样式不匹配。以下是修正后的完整实现,能精准匹配你需要的带圆角+右上角内凹的卡片样式:

修正后的代码

@Composable
fun CustomCard(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit,
) {
    // 普通圆角大小(除右上角外的其他圆角)
    val normalCornerRadius = with(LocalDensity.current) { 16.dp.toPx() }
    // 右上角内凹的半径(对应外部圆形标记的大小)
    val notchRadius = with(LocalDensity.current) { 40.dp.toPx() }
    val notchRadiusDp = 40.dp
    // 内凹与边缘的间距,确保圆形标记刚好贴合
    val notchOffset = with(LocalDensity.current) { 4.dp.toPx() }

    val shape = remember {
        GenericShape { size, _ ->
            val width = size.width
            val height = size.height

            // 左上角圆角
            moveTo(normalCornerRadius, 0f)
            quadraticTo(0f, 0f, 0f, normalCornerRadius)
            // 左侧边缘
            lineTo(0f, height - normalCornerRadius)
            // 左下角圆角
            quadraticTo(0f, height, normalCornerRadius, height)
            // 底部边缘
            lineTo(width - normalCornerRadius, height)
            // 右下角圆角
            quadraticTo(width, height, width, height - normalCornerRadius)
            // 右侧边缘到内凹位置
            lineTo(width, notchRadius + notchOffset)
            // 右上角内凹曲线:从右侧边缘向内凹中心过渡
            quadraticTo(
                width, notchOffset,
                width - notchRadius, notchOffset
            )
            // 内凹顶部曲线:从内凹中心向左回到顶部边缘
            quadraticTo(
                width - notchRadius * 2, notchOffset,
                width - notchRadius * 2, notchRadius + notchOffset
            )
            // 顶部边缘从内凹位置到左上角
            lineTo(normalCornerRadius, notchRadius + notchOffset)
            // 闭合路径
            close()
        }
    }

    Box(modifier = modifier) {
        Card(
            modifier = Modifier.fillMaxSize(),
            shape = shape,
            colors = CardDefaults.cardColors(containerColor = Color(0xFFBFE8FB))
        ) {
            content()
        }

        // 右上角圆形标记:刚好贴合内凹位置
        Box(
            modifier = Modifier
                .size(notchRadiusDp * 2 - 8.dp)
                .align(Alignment.TopEnd)
                .offset(x = (-4).dp, y = 4.dp)
                .background(color = Color.Blue, shape = CircleShape)
        ) {
            Text(
                text = "1",
                color = Color.White,
                modifier = Modifier.align(Alignment.Center),
                fontSize = 16.sp
            )
        }
    }
}

@Preview
@Composable
fun ContextCardPreview() {
    Column(modifier = Modifier.background(Color.Red)) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            CustomCard(
                modifier = Modifier
                    .width(200.dp)
                    .height(180.dp)
            ) {
                val price = buildAnnotatedString {
                    withStyle(SpanStyle(color = Color.Green)) { append("$") }
                    append("0.00")
                }

                val labelStyle = TextStyle(fontSize = 18.sp, fontWeight = FontWeight.Light)
                val priceStyle = TextStyle(fontSize = 18.sp, fontWeight = FontWeight.Bold)

                Column(modifier = Modifier.padding(16.dp)) {
                    Text(text = "Text", fontSize = 18.sp)

                    Spacer(modifier = Modifier.weight(0.8f))

                    Text(text = "Text", style = labelStyle)

                    Spacer(modifier = Modifier.weight(0.5f))
                    Text(text = price, style = priceStyle)
                }
            }
        }
    }
}

关键调整说明

  • 路径逻辑重构:重新梳理了GenericShape的绘制顺序,从左上角开始顺时针绘制,确保每个曲线和直线的衔接更自然,避免原代码中曲线参数混乱的问题。
  • 内凹弧度精准控制:右上角的内凹使用两段二次贝塞尔曲线实现,确保内凹弧度与外部圆形标记完全贴合,同时和卡片其他圆角保持视觉统一。
  • 参数解耦:将普通圆角、内凹半径、偏移量拆分为独立参数,方便后续调整样式,不用反复修改路径中的硬编码数值。
  • 圆形标记位置校准:通过offset调整圆形标记的位置,让它刚好嵌入卡片的内凹处,视觉上完全匹配目标效果。

内容的提问来源于stack exchange,提问作者rlaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:22:13