https://kotlinlang.org logo
c

Can

03/07/2021, 3:04 PM
Hey people! I feel like I'm missing something here. I'd like to apply a Porterduffmode / BlendMode to a Text so that it changes the color so that the lower half is white for example. Previously this could be achieved with "drawText" and a Porterduffmode but DrawScope doesn't support drawText and I feel like i can't apply a ColorFilter to Text. There might be some way by writing a custom Painter and add a colorfilter to it but this doesn't feel like a straightforward way to do this. Any ideas?
d

Denis

03/07/2021, 3:32 PM
Hi, Can. Have you seen https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/BlendMode? I haven't tried it and don't understand it yet, but looks like it's what you need. To draw text into Canvas, you should use TextDelegate. Search this channel for usage examples If you get it work, please share the code! Interesting question.
c

Can

03/07/2021, 3:39 PM
Hey Denis, thanks for the tip with TextDelegate - I think that's something I missed. I indeed found BlendMode but didn't manage to draw Text into a Canvas. I will definitely try it out!
@Denis are you sure "TextDelegate" is supposed to be used by API consumers? I get a scary looking warning
d

Denis

03/07/2021, 3:54 PM
@jim and @Siyamed talk about
TextDelegate
in this thread. I don't know if it won't change significantly in future releases. But basing on this message from @Adam Powell, there's no hidden magic (private APIs), and I think even if it'll change, it will stay accessible in some way. In the worst case you just copy the code to your project and keep using it. (Sorry for mentions, folks, but maybe you have something to add or correct me.)
a

Adam Powell

03/07/2021, 3:59 PM
"accessible in some way" in this case means you might need to copy/paste some of its implementation for stability across updates, its API is not stable/final for consumption as it is marked with
@InternalFoundationTextApi
🙏 2
c

Can

03/07/2021, 4:20 PM
@Adam Powell thanks for that! @Denis retried the code based on your suggestion and i feel like I'm doing something wrong. "DstAtop" is doing nothing at all, while I fee like it should do the trick:
Copy code
val displayedValue = displayedValue
        val textDelegate = if (displayedValue != null) {
            TextDelegate(
                text = AnnotatedString("${displayedValue / 1_000L}"),
                style = MaterialTheme.typography.h1.copy(fontWeight = FontWeight.Bold),
                density = Density(dm.density),
                resourceLoader = LocalFontLoader.current
            ).layout(Constraints(), LayoutDirection.Ltr)
        } else {
            null
        }
Canvas(
    Modifier.fillMaxSize()
) {
    if (textDelegate != null) {
        drawIntoCanvas {
            TextDelegate.paint(canvas = it, textDelegate)
        }
    }

    drawRect(
        color = Color.Red,
        topLeft = Offset(0f, 0f),
        size = Size(size.width, size.height),
        blendMode = BlendMode.DstAtop
    )
}
the bottom rect is not visible at all when setting "DstAtop". Can this be an emulator issue?
Got the effect i was looking for thanks to @romainguy. Seems like adding an alpha to my Canvas did the trick. This seems like its a quite hidden API and tricky to find tbh. Final code would be:
Copy code
Canvas(
    Modifier
        .fillMaxSize()
        .alpha(0.99f)
) {
    if (textDelegate != null) {
        drawIntoCanvas {
            TextDelegate.paint(canvas = it, textDelegate)
        }
    }

    drawRect(
        color = Color.White,
        topLeft = Offset(0f, size.height - boxHeight),
        size = Size(size.width, boxHeight),
        blendMode = BlendMode.SrcAtop
    )
}
FYI @Denis
Note ".alpha(0.99f)"
r

romainguy

03/07/2021, 7:46 PM
You shouldn't need this alpha trick
Using a layer is the proper way. @Nader Jawad can tell you more
Setting an alpha value has the side effect of creating a layer
n

Nader Jawad

03/07/2021, 7:54 PM
Yes, we need to have a transparent layer such that the text content can be used as a mask with the blendmode applied to it. As @romainguy mentioned, using alpha has a side effect of creating this layer. In the future there will be an explicit flag to force layer usage directly so using alpha as a side effect wouldn't be necessary.
🎉 2
c

Can

03/07/2021, 8:05 PM
Thanks a lot @Nader Jawad and @romainguy for your help
👍 4
2 Views