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

如何在Android Jetpack Compose中绘制单侧带曲线的盒子

在Jetpack Compose中绘制目标形状

你可以通过自定义Shape或直接使用Canvas来实现图中的形状,以下是两种实用方案:

方案一:自定义Shape(推荐用于可组合项背景)

自定义Shape可以直接应用到Modifier.background()中,适配各类布局场景:

import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Outline
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp

class CustomTopCutShape(
    private val cornerRadius: Float = 16.dp.toPx(),
    private val cutWidth: Float = 40.dp.toPx(),
    private val cutDepth: Float = 12.dp.toPx()
) : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        val path = Path().apply {
            // 起点:左下角
            moveTo(0f, size.height)
            // 左下角圆角
            lineTo(0f, cornerRadius)
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(0f, 0f, cornerRadius, cornerRadius),
                startAngleDegrees = 180f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            // 顶部左段直线到内凹起点
            lineTo(cutWidth, 0f)
            // 顶部左内凹圆角
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    cutWidth - cutDepth, 0f,
                    cutWidth + cutDepth, cutDepth
                ),
                startAngleDegrees = 270f,
                sweepAngleDegrees = -90f,
                forceMoveTo = false
            )
            // 顶部中间直线到右内凹起点
            lineTo(size.width - cutWidth, cutDepth)
            // 顶部右内凹圆角
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    size.width - cutWidth - cutDepth, 0f,
                    size.width - cutWidth + cutDepth, cutDepth
                ),
                startAngleDegrees = 180f,
                sweepAngleDegrees = -90f,
                forceMoveTo = false
            )
            // 顶部右段直线到右上角
            lineTo(size.width, 0f)
            // 右上角圆角
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    size.width - cornerRadius, 0f,
                    size.width, cornerRadius
                ),
                startAngleDegrees = 270f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            // 右下角直线到右下角圆角
            lineTo(size.width, size.height - cornerRadius)
            // 右下角圆角
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    size.width - cornerRadius, size.height - cornerRadius,
                    size.width, size.height
                ),
                startAngleDegrees = 0f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            // 闭合路径
            close()
        }
        return Outline.Generic(path)
    }
}

使用示例:

Box(
    modifier = Modifier
        .size(200.dp, 150.dp)
        .background(Color.Blue, shape = CustomTopCutShape())
)

方案二:使用Canvas直接绘制

如果需要更灵活的视觉控制(比如添加渐变、阴影),可以直接用Canvas组件绘制:

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.unit.dp

@Composable
fun CustomShapeCanvas() {
    val cornerRadius = 16.dp.toPx()
    val cutWidth = 40.dp.toPx()
    val cutDepth = 12.dp.toPx()
    
    Canvas(modifier = Modifier.size(200.dp, 150.dp)) {
        val width = size.width
        val height = size.height
        
        val path = Path().apply {
            moveTo(0f, height)
            lineTo(0f, cornerRadius)
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(0f, 0f, cornerRadius, cornerRadius),
                startAngleDegrees = 180f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            lineTo(cutWidth, 0f)
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    cutWidth - cutDepth, 0f,
                    cutWidth + cutDepth, cutDepth
                ),
                startAngleDegrees = 270f,
                sweepAngleDegrees = -90f,
                forceMoveTo = false
            )
            lineTo(width - cutWidth, cutDepth)
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    width - cutWidth - cutDepth, 0f,
                    width - cutWidth + cutDepth, cutDepth
                ),
                startAngleDegrees = 180f,
                sweepAngleDegrees = -90f,
                forceMoveTo = false
            )
            lineTo(width, 0f)
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    width - cornerRadius, 0f,
                    width, cornerRadius
                ),
                startAngleDegrees = 270f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            lineTo(width, height - cornerRadius)
            arcTo(
                rect = androidx.compose.ui.geometry.Rect(
                    width - cornerRadius, height - cornerRadius,
                    width, height
                ),
                startAngleDegrees = 0f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )
            close()
        }
        
        drawPath(path = path, color = Color.Blue)
    }
}

你可以根据图中实际比例,调整cornerRadius、cutWidth、cutDepth等参数,匹配目标形状。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:50:30