您可以使用Modifier.draBehind在Composables后面绘制边框,并判断您的Composable是在开始、中心还是结尾
enum class BorderOrder {
Start, Center, End
}
fun Modifier.drawSegmentedBorder(
strokeWidth: Dp,
color: Color,
cornerPercent: Int,
borderOrder: BorderOrder,
drawDivider: Boolean = false
) = composed(
factory = {
val density = LocalDensity.current
val strokeWidthPx = density.run { strokeWidth.toPx() }
Modifier.drawBehind {
val width = size.width
val height = size.height
val cornerRadius = height * cornerPercent / 100
when (borderOrder) {
BorderOrder.Start -> {
drawLine(
color = color,
start = Offset(x = width, y = 0f),
end = Offset(x = cornerRadius, y = 0f),
strokeWidth = strokeWidthPx
)
// Top left arc
drawArc(
color = color,
startAngle = 180f,
sweepAngle = 90f,
useCenter = false,
topLeft = Offset.Zero,
size = Size(cornerRadius * 2, cornerRadius * 2),
style = Stroke(width = strokeWidthPx)
)
drawLine(
color = color,
start = Offset(x = 0f, y = cornerRadius),
end = Offset(x = 0f, y = height - cornerRadius),
strokeWidth = strokeWidthPx
)
// Bottom left arc
drawArc(
color = color,
startAngle = 90f,
sweepAngle = 90f,
useCenter = false,
topLeft = Offset(x = 0f, y = height - 2 * cornerRadius),
size = Size(cornerRadius * 2, cornerRadius * 2),
style = Stroke(width = strokeWidthPx)
)
drawLine(
color = color,
start = Offset(x = cornerRadius, y = height),
end = Offset(x = width, y = height),
strokeWidth = strokeWidthPx
)
}
BorderOrder.Center -> {
drawLine(
color = color,
start = Offset(x = 0f, y = 0f),
end = Offset(x = width, y = 0f),
strokeWidth = strokeWidthPx
)
drawLine(
color = color,
start = Offset(x = 0f, y = height),
end = Offset(x = width, y = height),
strokeWidth = strokeWidthPx
)
if (drawDivider) {
drawLine(
color = color,
start = Offset(x = 0f, y = 0f),
end = Offset(x = 0f, y = height),
strokeWidth = strokeWidthPx
)
}
}
else -> {
if (drawDivider) {
drawLine(
color = color,
start = Offset(x = 0f, y = 0f),
end = Offset(x = 0f, y = height),
strokeWidth = strokeWidthPx
)
}
drawLine(
color = color,
start = Offset(x = 0f, y = 0f),
end = Offset(x = width - cornerRadius, y = 0f),
strokeWidth = strokeWidthPx
)
// Top right arc
drawArc(
color = color,
startAngle = 270f,
sweepAngle = 90f,
useCenter = false,
topLeft = Offset(x = width - cornerRadius * 2, y = 0f),
size = Size(cornerRadius * 2, cornerRadius * 2),
style = Stroke(width = strokeWidthPx)
)
drawLine(
color = color,
start = Offset(x = width, y = cornerRadius),
end = Offset(x = width, y = height - cornerRadius),
strokeWidth = strokeWidthPx
)
// Bottom right arc
drawArc(
color = color,
startAngle = 0f,
sweepAngle = 90f,
useCenter = false,
topLeft = Offset(
x = width - 2 * cornerRadius,
y = height - 2 * cornerRadius
),
size = Size(cornerRadius * 2, cornerRadius * 2),
style = Stroke(width = strokeWidthPx)
)
drawLine(
color = color,
start = Offset(x = 0f, y = height),
end = Offset(x = width -cornerRadius, y = height),
strokeWidth = strokeWidthPx
)
}
}
}
}
)
用法
@Composable
private fun SegmentedBorderSample() {
Row {
repeat(3) {
val order = when (it) {
0 -> BorderOrder.Start
2 -> BorderOrder.End
else -> BorderOrder.Center
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(40.dp)
.drawSegmentedBorder(
strokeWidth = 2.dp,
color = Color.Green,
borderOrder = order,
cornerPercent = 40,
drawDivider = false
)
.padding(4.dp)
) {
Text(text = "$it")
}
}
}
Row {
repeat(4) {
val order = when (it) {
0 -> BorderOrder.Start
3 -> BorderOrder.End
else -> BorderOrder.Center
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(40.dp)
.drawSegmentedBorder(
strokeWidth = 2.dp,
color = Color.Cyan,
borderOrder = order,
cornerPercent = 50,
drawDivider = true
)
.padding(4.dp)
) {
Text(text = "$it")
}
}
}
}
结果