在Jetpack Compose中从一个形状中剪切另一个形状

4

我对在Compose中制作这个视图有疑问,对于实现它没有任何想法。

视图

我的当前代码如下:

Box(
    modifier = Modifier
        .fillMaxSize()
        .height(300.dp)
) {
    Canvas(modifier = Modifier.matchParentSize()) {
        drawRoundRect(
            color = Color.Yellow,
            cornerRadius = CornerRadius(16.dp.toPx(), 16.dp.toPx())
        )
        drawRoundRect(
            color = Color.White,
            topLeft = Offset(
                x = size.width / 5,
                y = size.height - 60.dp.toPx()
            ),
            size = Size((size.width / 5) * 3, 50.dp.toPx() * 2),
            cornerRadius = CornerRadius(24.dp.toPx(), 24.dp.toPx()),
        )
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Text(
            text = "Test",
            modifier = Modifier.align(Alignment.BottomCenter)
        )
    }
}

以下是翻译的结果:

结果如下:

我的视图

2个回答

7

要从另一个路径中裁剪一些路径,您可以使用 clipPath

要添加外部圆角半径,您需要手动向路径添加弧线,就像这样:

Canvas(modifier = Modifier.matchParentSize()) {
    val outerCornerRadius = 16.dp.toPx()
    val clippedPath = Path().apply {
        val innerCornerRadius = 24.dp.toPx()
        val rectSize = Size(round((size.width / 5) * 3), round(50.dp.toPx() * 2))
        val rect = Rect(
            offset = Offset(
                x = (size.width - rectSize.width) / 2,
                y = size.height - rectSize.height
            ),
            size = rectSize
        )

        addRoundRect(
            RoundRect(
                rect,
                topLeft = CornerRadius(x = innerCornerRadius, y = innerCornerRadius),
                topRight = CornerRadius(x = innerCornerRadius, y = innerCornerRadius),
            )
        )
        val outerCornerDiameter = outerCornerRadius * 2
        val cornerSize = Size(outerCornerDiameter,outerCornerDiameter)
        val cornerOffset = Offset(outerCornerDiameter, outerCornerDiameter)
        val cornerYOffset = Offset(0f, outerCornerDiameter)
        moveTo(rect.bottomLeft - cornerYOffset)
        addArc(
            Rect(
                offset = rect.bottomLeft - cornerOffset,
                size = cornerSize
            ),
            startAngleDegrees = 0f,
            sweepAngleDegrees = 90f,
        )
        lineTo(rect.bottomLeft)

        moveTo(rect.bottomRight - cornerYOffset)
        addArc(
            Rect(
                offset = rect.bottomRight - cornerYOffset,
                size = cornerSize
            ),
            startAngleDegrees = 180f,
            sweepAngleDegrees = -90f,
        )
        lineTo(rect.bottomRight)
    }
    clipPath(clippedPath, clipOp = ClipOp.Difference) {
        drawRoundRect(
            color = Color.Yellow,
            cornerRadius = CornerRadius(outerCornerRadius, outerCornerRadius)
        )
    }
}

结果:


0

您还可以为您的 Composables 使用自定义形状来给它们一个特定的轮廓。只需扩展 Shape 接口并覆盖 createOutline() 方法。

例如:

对于角落,Path API 提供了一个 arcTo() 函数。然后,要绘制形状的边缘,请使用 lineTo() 方法。

class RoundedRectOutlinedCorner(
    private val cornerRadius: Dp = 16.dp,
    private val cutOutHeight: Dp = 60.dp,
    private val cutOutWidth: Dp = 145.dp
) : Shape {
    override fun createOutline(
        size: Size, layoutDirection: LayoutDirection, density: Density
    ): Outline {
        return Outline.Generic(Path().apply {
            val cornerRadius = with(density) { cornerRadius.toPx() }
            val cutOutHeight = with(density) { cutOutHeight.toPx() }
            val cutOutWidth = with(density) { cutOutWidth.toPx() }

            arcTo(
                rect = Rect(offset = Offset(0f, 0f), Size(cornerRadius, cornerRadius)),
                startAngleDegrees = 180f,
                sweepAngleDegrees = 90f,
                forceMoveTo = false
            )

            lineTo(size.width - cutOutWidth - cornerRadius, 0f)
            arcTo(
                rect = Rect(
                    offset = Offset(size.width - cutOutWidth - cornerRadius, 0f),
                    Size(cornerRadius, cornerRadius)
                ), startAngleDegrees = 270.0f, sweepAngleDegrees = 90f, forceMoveTo = false
            )

            lineTo(size.width - cutOutWidth, cutOutHeight - cornerRadius)
            arcTo(
                rect = Rect(
                    offset = Offset(size.width - cutOutWidth, cutOutHeight - cornerRadius),
                    Size(cornerRadius, cornerRadius)
                ), startAngleDegrees = 180.0f, sweepAngleDegrees = -90f, forceMoveTo = false
            )

            lineTo(size.width - cornerRadius, cutOutHeight)
            arcTo(
                rect = Rect(
                    offset = Offset(size.width - cornerRadius, cutOutHeight),
                    Size(cornerRadius, cornerRadius)
                ), startAngleDegrees = 270f, sweepAngleDegrees = 90f, forceMoveTo = false
            )

            lineTo(size.width, size.height - cornerRadius)
            arcTo(
                rect = Rect(
                    offset = Offset(size.width - cornerRadius, size.height - cornerRadius),
                    Size(cornerRadius, cornerRadius)
                ), startAngleDegrees = 0f, sweepAngleDegrees = 90f, forceMoveTo = false
            )

            lineTo(cornerRadius, size.height)
            arcTo(
                rect = Rect(
                    offset = Offset(0f, size.height - cornerRadius),
                    Size(cornerRadius, cornerRadius)
                ), startAngleDegrees = 90f, sweepAngleDegrees = 90f, forceMoveTo = false
            )
            close()
        })
    }
}

使用方法: 然后,您可以通过以下方式剪裁形状:

Modifier
    .height(250.dp)
    .clip(RoundedRectOutlinedCorner()),

或者使用.graphicsLayer/.background等。

结果:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接