如何绘制用分隔线绘制的圆形边框笔划?

Abd*_*511 2 android kotlin android-jetpack-compose

我正在尝试使用 Compose 实现这个自定义形状

收据图片

但由于某种原因,分隔符偏移圆用虚线绘制,这是代码

@Preview
@Composable
private fun ReceiptSeparator () {

    Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp) ,
        verticalAlignment = Alignment.CenterVertically  ,) {
        Box(
            modifier = Modifier
                .requiredSize(50.dp)
                .background(Color.White)
                .offset(-40.dp)
                .clip(CircleShape)
                .border(BorderStroke(2.dp, Color.Gray))

        ){}

        Box(
            Modifier
                .height(1.dp)
                .requiredWidth(250.dp)
                .weight(3f)
                .background(Color.Gray, shape = DottedShape(step = 20.dp))
        ){}
        Box(
            modifier = Modifier

                .offset(40.dp)
                .clip(CircleShape)
                .border(BorderStroke(2.dp, Color.Gray))
                .background(Color.White)
                .size(50.dp)
        ){}
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么圆是用虚线绘制的以及如何正确地实现这个形状?

Phi*_*hov 12

您的圆绘制不正确,因为Modifier.border默认情况下绘制一个矩形边框,然后您用Modifier.clip. 相反,如果您需要将形状应用于边框,则需要将形状传递到Modifier.border,如下所示:

.border(BorderStroke(2.dp, Color.Gray), shape = CircleShape)
Run Code Online (Sandbox Code Playgroud)

但这并不能解决你的问题。要像图像中所示正确绘制阴影,您需要将自定义形状应用到容器。

您可以使用Modifier.onGloballyPositioned来获取截止位置:

var separatorOffsetY by remember { mutableStateOf<Float?>(null) }
val cornerRadius = 20.dp
Card(
    shape = RoundedCutoutShape(separatorOffsetY, cornerRadius),
    backgroundColor = Color.White,
    modifier = Modifier.padding(10.dp)
) {
    Column {
        Box(modifier = Modifier.height(200.dp))
        Box(
            Modifier
                .padding(horizontal = cornerRadius)
                .height(1.dp)
                .requiredWidth(250.dp)
                // DottedShape is taken from this answer:
                // /sf/answers/4815244381/
                .background(Color.Gray, shape = DottedShape(step = 20.dp))
                .onGloballyPositioned {
                    separatorOffsetY = it.boundsInParent().center.y
                }
        )
        Box(modifier = Modifier.height(50.dp))
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此信息,您可以创建如下所示的形状:

class RoundedCutoutShape(
    private val offsetY: Float?,
    private val cornerRadiusDp: Dp,
) : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density,
    ) = Outline.Generic(run path@{
        val cornerRadius = with(density) { cornerRadiusDp.toPx() }
        val rect = Rect(Offset.Zero, size)
        val mainPath = Path().apply {
            addRoundRect(RoundRect(rect, CornerRadius(cornerRadius)))
        }
        if (offsetY == null) return@path mainPath
        val cutoutPath = Path().apply {
            val circleSize = Size(cornerRadius, cornerRadius) * 2f
            val visiblePart = 0.25f
            val leftOval = Rect(
                offset = Offset(
                    x = 0 - circleSize.width * (1 - visiblePart),
                    y = offsetY - circleSize.height / 2
                ),
                size = circleSize
            )
            val rightOval = Rect(
                offset = Offset(
                    x = rect.width - circleSize.width * visiblePart,
                    y = offsetY - circleSize.height / 2
                ),
                size = circleSize
            )
            addOval(leftOval)
            addOval(rightOval)
        }
        return@path Path().apply {
            op(mainPath, cutoutPath, PathOperation.Difference)
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

结果: