Jetpack Compose:使用透明颜色时在可组合边界之外绘图

问题描述 投票:0回答:1

我正在 Jetpack Compose 中创建一个自定义组件,需要在组件边界之外进行绘制,这可能会在 BlendMode 中使用透明颜色。我正在使用 CompositingStrategy 来处理这个问题,但面临一些问题。

下面是该问题的重现示例。

@Composable
@Preview(widthDp = 600, heightDp = 600)
private fun Preview() {
    Column(
        Modifier.fillMaxSize().background(Color.Blue),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Canvas(
            modifier = Modifier.size(250.dp).graphicsLayer(
                compositingStrategy = CompositingStrategy.Offscreen,
//                compositingStrategy = CompositingStrategy.ModulateAlpha
            ).border(1.dp, color = Color.Black)
        ) {
            drawCircle(
                Color.Red,
                (size.minDimension/2f)*1.5f
            )
            drawCircle(
                Color.Transparent,
                (size.minDimension/2f)*1f,
                blendMode = BlendMode.Src
            )
        }
    }
}

使用

CompositingStrategy.Offscreen
:正确处理 Alpha,但将绘图裁剪为组件的大小。

Result with CompositingStrategy.Offscreen

使用

CompositingStrategy.ModulateAlpha
:解决了剪切问题,但透明颜色内圆不起作用。

Result with CompositingStrategy.ModulateAlpha

那么有没有办法同时实现这两个目标呢?

下面是我期望的结果,其中内圈是透明的,所以蓝色背景是可见的:

Expected result

kotlin android-jetpack-compose drawing android-jetpack
1个回答
0
投票

您可以使用“差异”路径操作创建您提到的形状: 为外圆创建一条路径,为内圆创建一条路径,然后取两条路径之间的差值,这给出了您提到的形状。

代码:

@Composable
@Preview(widthDp = 600, heightDp = 600)
fun App() {
    Column(
        Modifier
            .fillMaxSize()
            .background(Color.Blue),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Canvas(
            modifier = Modifier
                .size(250.dp)
                .border(1.dp, color = Color.Black)
        ) {

            val cx = size.width/2f
            val cy = size.height/2f

            val c = Offset(cx, cy)

            val r = (size.minDimension/2f)

            val outerPath = Path().apply {
                addOval(
                    oval = Rect(
                        center = c,
                        radius = r*1.5f
                    )
                )
            }

            val innerPath = Path().apply {
                addOval(
                    oval = Rect(
                        center = c,
                        radius = r
                    )
                )
            }

            val path = Path().apply {
                op(outerPath, innerPath, PathOperation.Difference)
            }

            drawPath(
                path = path,
                color = Color.Red
            )
        }
    }
}

结果:

Demo

© www.soinside.com 2019 - 2024. All rights reserved.