Jetpack Compose Canvas drawText 颜色混合?

And*_*ill 3 android android-canvas android-jetpack-compose android-jetpack-compose-canvas

假设我在下面编写了以下代码。

背景洋红色圆圈,顶部有默认黑色的文本。

在此输入图像描述

当文本颜色位于圆圈上方时,我想将其混合为白色。

Canvas(
    modifier = Modifier.size(256.dp),
    onDraw = {
        drawCircle(
            color = Color.Magenta,
            radius = 50f,
            center = Offset(
                x = size.width / 2,
                y = size.height  / 2),
        )
        val textSize = textMeasurer.measure(text = AnnotatedString("A"))
        drawText(
            textMeasurer = textMeasurer,
            text = "A",
            style = TextStyle(
                color = Color.Black,
                fontSize = 14.sp
            ),
            topLeft = Offset(
                x = size.width / 2 - 100f - (textSize.size.width / 2),
                y = size.height  / 2 - (textSize.size.height / 2)
            )
        )
        drawText(
            textMeasurer = textMeasurer,
            text = "B",
            style = TextStyle(
                color = Color.Black,
                fontSize = 14.sp
            ),
            topLeft = Offset(
                x = size.width / 2 - (textSize.size.width / 2),
                y = size.height  / 2 - (textSize.size.height / 2)
            )
        )
    }
)
Run Code Online (Sandbox Code Playgroud)

我尝试过在许多不同的配置中在圆圈上使用 BlendMode,但我无法使其工作。而且drawText 没有我可以看到的混合模式。

有没有一种简单的方法来实现混合,使圆圈上方的文字变成白色?

Thr*_*ian 5

您要么需要设置 Composable 的 alpha,想要使用小于 1f 的 blendMode,要么使用想要在其中绘制源和目标的图层。降低 alpha 会在引擎盖下添加图层,这两者基本上是相同的事情。

Jetpack Compose 将 PorterDuffMode 应用于图像

如何剪辑或剪切可组合项?

fun DrawScope.drawWithLayer(block: DrawScope.() -> Unit) {
    with(drawContext.canvas.nativeCanvas) {
        val checkPoint = saveLayer(null, null)
        block()
        restoreToCount(checkPoint)
    }
}
Run Code Online (Sandbox Code Playgroud)

由于drawText没有 BlendMode 参数,我们需要将其绘制为目标,还添加了动画来通过 BlendMode 演示颜色变化。

在此输入图像描述

@Composable
private fun BlendModeSample() {

    val textMeasurer = rememberTextMeasurer()

    val infiniteTransition = rememberInfiniteTransition()


    val offset by infiniteTransition.animateFloat(
        initialValue = -1f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(durationMillis = 3000),
            repeatMode = RepeatMode.Reverse
        )
    )
    Canvas(
        modifier = Modifier.size(256.dp),
        onDraw = {

            val textSize = textMeasurer.measure(text = AnnotatedString("A"))
            drawText(
                textMeasurer = textMeasurer,
                text = "A",
                style = TextStyle(
                    color = Color.Black,
                    fontSize = 14.sp
                ),
                topLeft = Offset(
                    x = size.width / 2 - 100f - (textSize.size.width / 2),
                    y = size.height / 2 - (textSize.size.height / 2)
                )
            )


            drawWithLayer {

                // Destination
                drawText(
                    textMeasurer = textMeasurer,
                    text = "B",
                    style = TextStyle(
                        color = Color.Black,
                        fontSize = 14.sp
                    ),
                    topLeft = Offset(
                        x = size.width / 2 - (textSize.size.width / 2),
                        y = size.height / 2 - (textSize.size.height / 2) + offset * 100f
                    ),

                    )

                // Source
                drawCircle(
                    color = Color.Magenta,
                    radius = 50f,
                    center = Offset(
                        x = size.width / 2,
                        y = size.height / 2
                    ),
                    blendMode = BlendMode.SrcOut
                )
            }


        }
    )
}
Run Code Online (Sandbox Code Playgroud)

您还可以查看使用混合模式来构建评级栏。

Jetpack Compose:如何创建评级栏?