简体   繁体   中英

Jetpack Compose Canvas drawText color blending?

Assume I have the following code in compose below.

A background magenta circle with a text on top with a default black color.

在此处输入图像描述

I would like to blend the text color to White when it is above the circle.

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)
            )
        )
    }
)

I have tried using BlendMode on the cirle in a lot of different configurations but I'm unable to make it work. And drawText doesn't have a blend mode that I can see.

Is there an easy way to achieve blending to make the text above the circle white?

You either need to set alpha of Composable you want to use blendMode with less than 1f or use layer you want to draw source and destination in. Lowering alpha adds layer under the hood which both are basically same thing.

Jetpack Compose Applying PorterDuffMode to Image

How to clip or cut a Composable?

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

Since drawText doesn't have blendMode parameter we need to draw it as destination, also added animation to demonstrate color changes via 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
                )
            }


        }
    )
}

You can also check out using blend modes to build a rating bar.

Jetpack Compose: How to create a rating bar?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM