Looking to top align the characters of two `Text`s...
# compose-android
k
Looking to top align the characters of two `Text`s where each
Text
has a different font size.
Is this not possible?
Copy code
Row(verticalAlignment = <http://Alignment.Top|Alignment.Top>) {
    Text(
        text = "${it.toInt()}",
        style = MaterialTheme.typography.headlineMedium.merge(
            TextStyle(
                platformStyle = PlatformTextStyle(includeFontPadding = false),
                lineHeightStyle = LineHeightStyle(
                    alignment = <http://LineHeightStyle.Alignment.Top|LineHeightStyle.Alignment.Top>,
                    trim = LineHeightStyle.Trim.FirstLineTop
                )
            )
        ),
    )
    Text(
        text = "°F",
        style = MaterialTheme.typography.bodyLarge.merge(
            TextStyle(
                platformStyle = PlatformTextStyle(includeFontPadding = false),
                lineHeightStyle = LineHeightStyle(
                    alignment = <http://LineHeightStyle.Alignment.Top|LineHeightStyle.Alignment.Top>,
                    trim = LineHeightStyle.Trim.FirstLineTop)
            )
        ),
    )
}
Here’s the unexpected resulting preview:
Followed this blog post https://medium.com/androiddevelopers/fixing-font-padding-in-compose-text-768cd232425b and it got me close, but not quite there… Anyone have any ideas?
r
Are you trying to align the top of the two
Text()
items?
k
@romainguy, I believe I’ve achieved that. Now what I want is for the tops of the text characters to be aligned.
(notice how the degrees F is floating higher than the numbers)
It appears that even with
includeFontPadding
set to
false
and using
Trim.firstLineTop
, there is still some amount of padding, where the characters don’t make it quite all the way to the top of their container. At least that’s how it appears to me given the preview. No?
r
Yeah that's what I meant, you want the pixels of the text to be aligned
💯 1
k
For those playing along at home, this is what I ended up with:
Copy code
Row(verticalAlignment = Alignment.CenterVertically) {
    Text(
        text = "${it.toInt()}",
        style = MaterialTheme.typography.headlineMedium
    )
    Text(
        text = "°F",
        style = MaterialTheme.typography.bodyLarge.merge(
            TextStyle(
                platformStyle = PlatformTextStyle(includeFontPadding = false),
                lineHeightStyle = LineHeightStyle(
                    alignment = <http://LineHeightStyle.Alignment.Top|LineHeightStyle.Alignment.Top>,
                    trim = LineHeightStyle.Trim.FirstLineTop
                )
            )
        ),
    )
}
I get the feeling I might be getting lucky, but if someone knows otherwise, I’d love to know what we can point to that demonstrates this really is the proper way to do it if in fact this will work no matter how the fonts/sizes change…?
z
I don’t think centering is guaranteed to work… @Halil Ozercan do you have any better ideas?
r
I ran into this myself when trying to do something for https://github.com/romainguy/combo-breaker. I couldn’t find a way to completely get rid of top/bottom padding
One solution is to draw 75F directly with
Canvas
where you can control positioning down to the pixel
z
Yep and https://developer.android.com/reference/kotlin/androidx/compose/ui/text/TextMeasurer will give you access to font metrics for the measured text so you can do whatever you like. But then you’ll need to make sure to handle semantics yourself
h
AFAIK there is no perfect way of fully removing paddings of each glyph or counting for them. Even fontMetrics won't give you the absolute top position of each character. One ultra hacky way I can think of is to intercept the draw phase of text composable and record it into a Picture/Bitmap. Then you can find the first pixel from top that is actually filled (this is probably going to be where antialiasing begins). Solutions that are using the conventional APIs are always going to be restricted by the font itself.
r
@Halil Ozercan You don't need a Bitmap, you can do this easily by getting a Path outline of the text. The path bounds will you give exactly the bounds of the glyphs
h
🤦 yep, that's much better! I always forget about the path API.
c
i had to do this as well recently. and i think i got to a pretty good spot by just taking the delta between the two font sizes and then just setting a spacer to that height. 🤷
r
Use Path 😇
👍 1