如何在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
相关产品推荐
相关产品推荐

