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

Jetpack Compose:实现带弧形边框的CardView

实现Jetpack Compose Card自定义弧形边框的思路

核心思路:自定义绘制或自定义Shape

Jetpack Compose默认Card的边框是完整矩形,要实现目标弧形缺口边框,可通过以下两种方案实现:

方案一:用drawBehind手动绘制边框

这种方式能精确控制边框每一段的样式,包括弧形缺口的位置和大小,适合需要灵活调整的场景:

Card(
    modifier = Modifier
        .size(200.dp, 150.dp)
        .drawBehind {
            val strokeWidth = 2.dp.toPx()
            val arcRadius = 16.dp.toPx()
            val halfStroke = strokeWidth / 2

            // 定义边框线段的起止点(避开弧形缺口区域)
            val topStart = Offset(halfStroke, halfStroke + arcRadius)
            val topEnd = Offset(size.width - halfStroke - arcRadius, halfStroke)
            val rightTop = Offset(size.width - halfStroke, halfStroke + arcRadius)
            val rightBottom = Offset(size.width - halfStroke, size.height - halfStroke - arcRadius)
            val bottomEnd = Offset(size.width - halfStroke - arcRadius, size.height - halfStroke)
            val bottomStart = Offset(halfStroke + arcRadius, size.height - halfStroke)
            val leftBottom = Offset(halfStroke, size.height - halfStroke - arcRadius)
            val leftTop = Offset(halfStroke, halfStroke + arcRadius)

            // 绘制四条直边框
            drawLine(Color.Gray, topStart, topEnd, strokeWidth)
            drawLine(Color.Gray, rightTop, rightBottom, strokeWidth)
            drawLine(Color.Gray, bottomEnd, bottomStart, strokeWidth)
            drawLine(Color.Gray, leftBottom, leftTop, strokeWidth)

            // 绘制四个角的向内凹弧形缺口
            drawArc(
                color = Color.Gray,
                startAngle = 180f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset(halfStroke, halfStroke),
                size = Size(arcRadius * 2, arcRadius * 2),
                style = Stroke(strokeWidth)
            )
            drawArc(
                color = Color.Gray,
                startAngle = 270f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset(size.width - halfStroke - arcRadius * 2, halfStroke),
                size = Size(arcRadius * 2, arcRadius * 2),
                style = Stroke(strokeWidth)
            )
            drawArc(
                color = Color.Gray,
                startAngle = 0f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset(size.width - halfStroke - arcRadius * 2, size.height - halfStroke - arcRadius * 2),
                size = Size(arcRadius * 2, arcRadius * 2),
                style = Stroke(strokeWidth)
            )
            drawArc(
                color = Color.Gray,
                startAngle = 90f,
                sweepAngle = 90f,
                useCenter = false,
                topLeft = Offset(halfStroke, size.height - halfStroke - arcRadius * 2),
                size = Size(arcRadius * 2, arcRadius * 2),
                style = Stroke(strokeWidth)
            )
        },
    backgroundColor = Color.White,
    elevation = 4.dp
) {
    Text("自定义弧形边框Card", modifier = Modifier.padding(16.dp))
}

方案二:自定义Shape结合border修饰符

如果需要Card的整体形状(包括阴影、点击区域)跟随弧形缺口,可自定义Shape,再给Card添加边框:

class ArcGapShape(private val arcRadius: Dp) : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        val radius = arcRadius.toPx(density)
        val path = Path().apply {
            // 从顶部缺口右侧开始绘制路径
            moveTo(radius, 0f)
            lineTo(size.width - radius, 0f)
            // 右上角弧形
            arcTo(
                rect = Rect(size.width - 2*radius, 0f, size.width, 2*radius),
                startAngleDegrees = 270f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            lineTo(size.width, size.height - radius)
            // 右下角弧形
            arcTo(
                rect = Rect(size.width - 2*radius, size.height - 2*radius, size.width, size.height),
                startAngleDegrees = 0f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            lineTo(radius, size.height)
            // 左下角弧形
            arcTo(
                rect = Rect(0f, size.height - 2*radius, 2*radius, size.height),
                startAngleDegrees = 90f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            lineTo(0f, radius)
            // 左上角弧形
            arcTo(
                rect = Rect(0f, 0f, 2*radius, 2*radius),
                startAngleDegrees = 180f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            close()
        }
        return Outline.Generic(path)
    }
}

// 使用示例
Card(
    modifier = Modifier
        .size(200.dp, 150.dp)
        .border(2.dp, Color.Gray, ArcGapShape(16.dp)),
    shape = ArcGapShape(16.dp),
    backgroundColor = Color.White,
    elevation = 4.dp
) {
    Text("自定义Shape实现边框", modifier = Modifier.padding(16.dp))
}

调整提示

  • 修改arcRadius参数可控制弧形缺口的大小,strokeWidth控制边框粗细,适配你的需求。
  • 若需要弧形缺口在边的中间而非角落,只需调整drawBehind中的线段起止点或Shape路径的节点位置即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 03:15:39