Hello, I have issues with the rendering of a rotat...
# compose
n
Hello, I have issues with the rendering of a rotating
Text
composable in Android. The letters "giggle" / "snap" between 2 y values it seems, that's really noticeable. It feels like text is handled differently in Compose. Is it possible to "rasterize" the Text composable and just rotate the pixels (even if it creates some aliasing)? Here a small reproductible example (with a simple colored square that is working perfectly fine).
Copy code
Column(
    modifier = Modifier.fillMaxSize(),
    verticalArrangement = Arrangement.SpaceEvenly,
    horizontalAlignment = Alignment.CenterHorizontally,
) {
    val angle by rememberInfiniteTransition().animateFloat(
        initialValue = 0F,
        targetValue = 10F,
        animationSpec = infiniteRepeatable(
            animation = tween(
                durationMillis = 50_000,
                easing = LinearEasing,
            ),
            repeatMode = RepeatMode.Reverse,
        )
    )

    Text(
        modifier = Modifier
            .graphicsLayer {
                rotationZ = angle
            }
            .padding(64.dp),
        text = "I'm a text that giggle all around, unlike this box down here :( -_| ",
        textAlign = TextAlign.Center,
        fontSize = 20.sp
    )

    Box(
        modifier = Modifier
            .graphicsLayer {
                rotationZ = angle
            }
            .size(200.dp)
            .background(Color.Magenta),
    )
}
r
You can try two things:
• Linear text
• Set your graphicsLayer to have an Offscreen compositing strategy
#2 is what you are asking for, but #1 should fix it as well without generating an extra offscreen texture
n
As always, thanks Romain for the tips,
compositingStrategy = CompositingStrategy.Offscreen
is exactly what fixes my problem. But I don't understand why rendering the text in an offscreen buffer fixes the text "snapping". Any clues? 😄 Also, "linear text compose" doesn't bring anything, am I missing something?
r
Because when using an offscreen layer the text is rasterized into a texture, and the texture is rotated
when you don't do this, the text is re-rasterized at different rotation angles, which when combined with hinting, etc. causes the wiggle
Linear text effectively prevents this
Here's a way to enable linear text:
Copy code
ProvideTextStyle(
  TextStyle(textMotion = Animated)
) {
  Text(…)
}
n
I see, thanks! I guess the "cost" of
compositingStrategy = CompositingStrategy.Offscreen
is the fact we have to render "twice" this Composable, right?
r
Well you render it once the first time (or every time the content changes), then the texture is copied on every frame
So in the worst case, yeah you draw twice
But also you use more memory
It can also look "bad" if you start scaling for instance
n
Yes, makes sense. Thanks a lot for your quick help 😄 I just looked for the other solution you cited (
TextMotion.Animated
), and it all boils down to good old Canvas with
LINEAR_TEXT_FLAG
and
SUBPIXEL_TEXT_FLAG
💯 1
r
Yep, hence my mention of linear text
n
Yeah, I didn't see the relation between the "Compose world" and the Canvas flags 😅 But in the end, Compose is just a big Canvas
r
Views are just a big Canvas
h
"Scaled" in the title is just one example, the same thing of course applies to translation and rotation