I have this design that I recreated from figma/ske...
# compose
c
I have this design that I recreated from figma/sketch from my designer. These two text fields don't have any spacers between them in sketch. It looks like it's just line height that's being taken into account... but my composable ends up looks squished. Like it's right on top of each other with no space. The only idea I have in mind is that compose/android doesn't "show" the space below a line if it's a single line? Because this type style does indeed have line spacing added in the Type delcaration, but it just doesn't seem to have it at runtime. It's part of our design system and so I can't quite rip it out in order to create a minimal reproducible sample, but I was curious if anyone had any ideas. I know compose doesn't have an option to disable fontPadding, but in this case... it's almost like I expected even more font padding. @Siyamed any thoughts? I know I talked about this to you on twitter I think like monttttths ago as one of my worst things in the current view based system is matching my designers with text. There's always some slight spacing issue. iOS seems to look just fine and so now I have to manually put in paddingBottom on the top Text. thanx
πŸ‘€ 1
s
Can you share the code please; unclear what's going on here from screenshot
c
@Sean McQuillan [G] will do. Give me a few moments to pull together a minimal sample.
πŸ‘ 1
@Sean McQuillan [G] alright so this is what my designer gave me
Header and Article Title doesn't have any spacer declared
Header is defined as such
Copy code
val header = TextStyle(
        fontFamily = Rubik,
        fontSize = 14.sp,
        fontWeight = FontWeight.Normal,
        lineHeight = 22.sp,
        letterSpacing = (-0.24).sp
    )
Article Title is defined as such
Copy code
val article = TextStyle(
        fontFamily = Rubik,
        fontSize = 18.sp,
        fontWeight = FontWeight.Medium,
        lineHeight = 24.sp,
        letterSpacing = (-0.31).sp
    )
Here is my composable
Copy code
@ExperimentalMaterialApi
@Composable
fun ArticleItem(
    header: String,
    articleTitle: String,
    articlePreview: String,
) {
    Card(
        modifier = Modifier.padding(horizontal = 16.dp),
    ) {
        Column {
            Box(
                modifier = Modifier
                    .aspectRatio(16 / 9F)
                    .background(Color.Gray),
            )
            Column(Modifier.padding(horizontal = 24.dp)) {
                Spacer(Modifier.height(24.dp))
                Text(
                    header,
                    style = CustomTypeScale.header,
                    maxLines = 1,
                    color = Color(0xff212121),
                    overflow = TextOverflow.Ellipsis
                )
                Text(
                    articleTitle,
                    color = Color(0xff00B4FF),
                    style = CustomTypeScale.article,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
                Spacer(Modifier.height(24.dp))
                Text(
                    articlePreview,
                    maxLines = 5,
                    style = CustomTypeScale.header,
                    color = Color(0xff212121),
                    overflow = TextOverflow.Ellipsis,
                )
                Spacer(Modifier.height(24.dp))
            }
        }
    }
}
The design (left) vs my composable (right) looks off, but my designer is really skeptical about the "Header" and the "Article Title" and the seemingly missing space that is there on the sketch file.
@Sean McQuillan [G] hope that helps and it's not information overload! This would happen to me in the view system a lot where it's really hard to align text properly but I really thought that compose be an improvement.
s
Thanks!
I'll take a deeper look this afternoon. As a Q is the designer comfortable speccing firstBaseline offsets?
c
Erm. I've never heard of that... but I will have to ask the designer. 1 sec
s
Oh; what are CustomTypeScale.header/article/header
c
Copy code
object CustomTypeScale {
    val header = TextStyle(
        fontFamily = Rubik,
        fontSize = 14.sp,
        fontWeight = FontWeight.Normal,
        lineHeight = 22.sp,
        letterSpacing = (-0.24).sp
    )
    val article = TextStyle(
        fontFamily = Rubik,
        fontSize = 18.sp,
        fontWeight = FontWeight.Medium,
        lineHeight = 24.sp,
        letterSpacing = (-0.31).sp
    )
    val body = TextStyle(
        fontFamily = Rubik,
        fontSize = 14.sp,
        fontWeight = FontWeight.Normal,
        lineHeight = 22.sp,
        letterSpacing = (-0.24).sp
    )
s
Any padding might end up in line height or font padding
By line height i mean where exactly the line height is applied
πŸ€” 1
I didnt understand the issue very well yet, but wanted to jump in with suspects
c
Please let me know if you need any other details. I feel like I'm doing something very wrong. Apparently web and ios look good (the CustomTypeStyle delcarations seem to match 1:1 with sketch).
s
Looking at the design I think you missed a 24.dp padding on top. I'd need to dig in more about how web/ios do line-height, but it's not impacting the padding of a single line here. In Compose, I'd generally recommend doing any specific vertical text layout using alignment lines which you can do using
Modifier.paddingFromBaseline(top=, bottom=)
Our typography is built around baseline positions
Here's a quick chop showing how you can apply baseline positioning here (a bit of eyeballing the pixels, design review needed πŸ˜„ )
Copy code
@ExperimentalMaterialApi
@Composable
fun ArticleItem(
    header: String,
    articleTitle: String,
    articlePreview: String,
) {
    Card(
        modifier = Modifier.padding(horizontal = 16.dp),
    ) {
        Column {
            Box(
                modifier = Modifier
                    .aspectRatio(16 / 9F)
                    .background(Color.Gray),
            )
            Column(Modifier.padding(24.dp)) {
                Text(
                    header,
                    style = CustomTypeScale.header,
                    color = Color(0xff212121),
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.paddingFromBaseline(top = 26.sp) // after the 24.dp padding
                )
                Text(
                    articleTitle,
                    color = Color(0xff00B4FF),
                    style = CustomTypeScale.article,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.paddingFromBaseline(top = 24.sp)
                )
                Spacer(Modifier.height(24.dp))
                Text(
                    articlePreview,
                    maxLines = 5,
                    style = CustomTypeScale.body,
                    color = Color(0xff212121),
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.paddingFromBaseline(top = 22.sp)
                )
            }
        }
    }
}
I would love to hear how your designer feels about being able to position baselines like this, and if it's a spec they're comfortable producing.
c
@Sean McQuillan [G] interesting... so I can't set paddingFromBaseline on a type style itself?
Also... I think we're all being misled by the Spacer/padding? Here is a simplified look that still shows the problem.
See an update "potential" design from my designer (sketch screenshot showing that each piece of text is right up against each other). Basically solely relying on a piece of texts line height for the "space" between different pieces of text
Here it is running (same code as above, but I just removed the 3 spacers)
So overall, everything just looks "tighter" to me. As if translating the line height from sketch into my composable doesn't really work.
s
I don't believe lineHeight has any impact on the first baseline here
e.g. change it to 100.sp and you won't see any change
Can you file a bug in the Jetpack Compose component with your expectations here (line-height is treated as min-height for Text composable). I'm not sure that's the right API but it'll capture this discussion. https://issuetracker.google.com/components/612128
c
Interesting... So no way around this? Like no way to enable leading line height? Or just in general some kind of text style attribute?
I guess I can make a custom text that takes this into account. But okay. Bug report it is!
s
Copy code
@Composable
fun LineHeightSizedText(text: String) {
    with(LocalDensity.current) {
        Text(
            text,
            style = CustomTypeScale.header,
            color = Color(0xff212121),
            maxLines = 1,
            overflow = TextOverflow.Ellipsis,
            modifier = Modifier.defaultMinSize(
                minHeight = CustomTypeScale.header.lineHeight.value.toDp()
            )
        )
    }
}
Is what comes to mind πŸ˜„
But yea, I'd say ask your designer to use baseline positions instead of line height to do styling like this. I'm kind of suspicious that 24.sp is the actual line-height gap presented padding in the comped design between header and title; and I think there's some implicit padding differences here that will likely stick around
c
24.dp was just an off the cuff value in the first sample. I was mostly trying to draw attention to header and article title.
I will have to follow up with my designer to see what their expectations are. Again, the only thing that is inconvenient is the fact that this apparently works correctly on other platforms, so Android looks like the black sheep.
Thanks for your time Sean!
s
Thanks for the bug report!
(Text is hard, feedback needed πŸ™‚ )
βž• 1
c
Other designer here πŸ‘‹ - I don't think Sketch or Figma support baseline padding. It's just height and line height. And font size.
πŸ‘ 1
I'm not sure how cleanly Figma/Sketch specs map to iOS and web for you, but for me in the past it was never 100% even with web, and you end up eyeballing and nudging.
We tend to reference back to this article about the challenges with line height and design tools: https://www.figma.com/blog/line-height-changes/
Ironically the Material Design guidelines reference baseline padding a lot, which from a parameters/properties POV is readily available in Android but not in web (not sure about iOS), AND isn't really available to configure in design tools outside of Adobe, i.e. Sketch/Figma. You can certainly create "baseline grids" in Figma to help align things visually, but you can't actually modify the properties of Text elements in the tool to include baseline padding...
c
@Chris Sinco [G] That article is great! In short though, are you basically saying that there's no real unifying way to do this across figma/sketch and ios/web/android? I wish there was just like docs on sketch/figma that told us how to tweak our styles per platform in order to get it to match exactly. In my case, I think I'd be okay with going Seans route of creating a new MyText composable that basically calculates/takes into account the differences between sketch and compose, and then I would just replace all instances of Text with MyText. πŸ˜„
@Chris Sinco [G] also seems that the figma article links to this https://aresluna.org/line-height-playground/ which basically shows that Android requires a Y vertical adjustment.
c
are you basically saying that there’s no real unifying way to do this across figma/sketch and ios/web/android?
I don’t think it’s impossible, but it would require work and awareness from the design tools companies to address this, especially when they provide inspect and code gen tools for designer -> developer handoff. Like here, you can see the code suggestions from Figma vary quite a bit depending on platform:
c
Oooh. Figma includes a negative translation y. I wonder if that makes up for why android looks like it's missing some padding at the top.
Also. Fun twist in the story. The ios team was indeed actually adding additional padding themselves. Now that both platforms removed padding, we look identical to each other, BUT still different from sketch. So our designer is having us create a Text component that automatically inserts some padding at the top. I don't know how to calculate it yet (I'll take suggesstions if it should be based on line height or size of font, etc) but yeah. Progress I guess.
πŸ˜… 2
s
Cheeky padding πŸ˜„
@Colton Idle did you get a chance to file a bug? I want to make sure it gets triaged correctly πŸ™‚.
c
@Sean McQuillan [G] at this point I have not because I don't even know right from wrong anymore. I am very happy that iOS and Android do look identical and it means that we're setting our values correctly, but at this point, I wish there was an option in sketch to remove that top padding. We've been looking and apparently you can't remove it? So we're trying their support team now... πŸ˜„
s
hah ok
c
The main question mostly spurred from the fact that the ios team (wrongly) informed me that they didn't add any additional spacing so when it looked perfect on ios and sketch then android was the odd one out.
Now that ios removed all the padding, ios and android look the same. so thats good. But I need to either figure out how to disable the top padding in sketch, or we will create a new Text composable (Or I'll dig into a TextStyle) to see if we can basically make a
SketchText
composable which will take the same attributes, but will calculate that top padding the same as sketch does.
oooh. @Sean McQuillan [G] and @Siyamed wonder what you think about that gist above ^
t
Condensed this into a modifier, and center the layout in the padded bounds to match Figma:
Copy code
fun Modifier.fillLineHeight(
    lineHeight: TextUnit = TextUnit.Unspecified
): Modifier = composed(debugInspectorInfo {
    name = "fillLineHeight"
    value = lineHeight
}) {
    val resolvedLineHeight = lineHeight.takeOrElse { LocalTextStyle.current.lineHeight }
    if (resolvedLineHeight.isSpecified) {
        val lineHeightPx = with(LocalDensity.current) { resolvedLineHeight.roundToPx() }
        Modifier.layout { measurable, constraints ->
            val placeable = measurable.measure(constraints)
            val space = (lineHeightPx - placeable.height % lineHeightPx) % lineHeightPx
            layout(placeable.width, placeable.height + space) {
                placeable.place(0, space / 2)
            }
        }
    } else {
        Modifier
    }
}
πŸ‘πŸΌ 1
πŸ‘ 1
s
Really digging this thread
βž• 4
c
Since the Modifier mentioned above did not work for the Font we use I did a little digging and compiled my results in this article πŸ™‚ Writing it really helped getting a clearer picture of the differences between Android and Figma. I’ll be happy for feeedback as well!
c
OH HECK YEAH. This is awesome @Can!
❀️ 1
@Siyamed sorry for the ping, but curious on your thoughts on this since it was almost a year ago since i gave up trying to have my figma deisgn specs match android+compose
c
@Colton Idle I feel like the Compose Text team (especially @Siyamed) currently actively takes on this issue - Compose 1.2.0 is filled with changes that underline this assumption! E.g. this new line-height prototype gives us the possibility to get closer to Figma designs - this is Siyameds work πŸ™‚
πŸ‘ 1
So if you are not in a hurry just wait for the new β€œExperimentalTextApi” to be released, I feel like it contains everything we need to achieve 100% fidelity
s
Thanks Can. Yes i very very recently played with it. It looked promising with a few details to figure out.
What triggered me to take a look was a comment on includefontpadding work: setting the line height for includeFontPadding. it doesn't work for single line text and the first line of any text
t
Yep, this is tripping me up right now too
s
I am looking for ways how to share design docs (or short docs describing in detail) but i dont have a solution for that yet
I understand Tad. It tripped me as well at least a few times :)
t
Yeah, that Modifier I posted has been working well for us, but now it's a bit more complicated to "center" the first line's text in its lineHeight
I'll take a look at your CL, maybe I can pull something from it
s
😞
it looks like the ticket on the CL shared is public. there is a video there.
Your feedback is more than welcome, actually it is needed πŸ™‚
t
I think those knobs are pretty much ideal
As long as I can achieve what CSS does (split the extra space above and below each line) then this would work
AFAICT that's what Figma is doing
s
to be honest: I do not think in the perspective of we need to do what figma does. It looks like a common need, figma is an input. but how web behaves, or other platforms, what i.e. Google Docs does etc are all input.
t
Yeah, I'm most interested in matching the designs I receive, and that happens to use the CSS "half-leading" behavior
Anyway, here's an updated Modifier that appears to work for our font:
Copy code
fun Modifier.fillLineHeight(
    lineHeight: TextUnit = TextUnit.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified
): Modifier = composed(
    debugInspectorInfo {
        name = "fillLineHeight"
        value = lineHeight
        properties["lineHeight"] = lineHeight
        properties["fontSize"] = fontSize
    }
) {
    val resolvedFontSize = fontSize.takeOrElse { LocalTextStyle.current.fontSize }
    val resolvedLineHeight = lineHeight.takeOrElse { LocalTextStyle.current.lineHeight }
    if (resolvedLineHeight.isSpecified) {
        layout { measurable, constraints ->
            val fontSizePx = resolvedFontSize.roundToPx()
            val lineHeightPx = resolvedLineHeight.roundToPx()
            val placeable = measurable.measure(constraints)
            val firstLineBottom = placeable[FirstBaseline]
            val firstLineTop = firstLineBottom - fontSizePx
            val space = (lineHeightPx - placeable.height % lineHeightPx) % lineHeightPx
            layout(placeable.width, placeable.height + space) {
                placeable.place(0, (space - firstLineTop) / 2)
            }
        }
    } else {
        this
    }
}
s
Yeah, the issue is the tool and how we get the designs might change tomorrow, something can become more famous than the one we have today. so then we would be re-checking to see how we can match to the new design tool. That is what I am afraid of πŸ™‚
βž• 2
c
@tad β€œCentering” inside the line only behaves well if your font has ascent/descent values which are close to the top/bottom fontmetrics when working with font-padding. That approach however is ideal when turning font-paddings off. @Siyamed I believe that CSS, Figma and Sketch all behave the same, whereas iOS and Android use a different strategy for the first line. It appears to me that the new
LineHeightBehevaiour
is reflecting this quite nicely πŸ™‚
πŸ‘ 2
c
Yeah, I found it weird that android has this special case if its only a single line then it does different stuff. Hm. I've got a lot to learn! All in all, having a resource like this where I can make android designs closer to figma is awesome. It reminds me of this great article: https://medium.com/@nathangitter/why-your-app-looks-better-in-sketch-3a01b22c43d7 Most of the time. I'm moving things from figma to compose and so its nice to know how to get these things to look like another
❀️ 1
πŸ‘ 1
s
Line height alignment and trimming apis are merged btw. Fingers crossed.
They should be available in the next release beta2 i believe
❀️ 2
πŸŽ‰ 3
@Can fyi
c
That is awesome news! I will try to write a sequel to my article in the upcoming weeks and see if I can give some guidance with the new API. But last I checked it was perfect!
πŸ’― 2
K 1
c
Please make sure to post it in this thread too. πŸ˜„
πŸ˜„ 1
c
Definitely will - let’s see when beta2 gets released πŸ™‚
s
This is out in androidx.compose.ui:ui-*:1.2.0-beta01
c
Just saw! Thanks for your awesome work @Siyamed. I will try the binary out next week πŸŽŠπŸŽ‰
❀️ 1
πŸ‘ 1
s
Please play with it an let us know about the issues, api etc.
t
!! thank you!
❀️ 1
s
Hopefully it will match the expectations, otherwise let us know.
c
Definitely awaiting what @Can thinks. πŸ˜… I'm away on vacation and i cant test at the moment.
πŸ‘ 1
I'm still away on vacation but couldn't wait to get my hands on it. @Siyamed is this pretty much the right api to be using if I want line height to be applicable to singline text + i want to disable font padding?
Copy code
val H1 =
    TextStyle(
      lineHeightStyle = LineHeightStyle(
        alignment = LineHeightStyle.Alignment.Center,
        trim = LineHeightStyle.Trim.None
      ),
      platformStyle = PlatformTextStyle(includeFontPadding = false),
      fontFamily = MyRoboto,
      fontSize = 36.sp,
      fontWeight = FontWeight.Bold,
      lineHeight = 40.sp,
    )
s
Yes !
As you did there, i would expect those to be mostly set in the theme since possibly a dev would like most text lineHeights to behave the same.
c
Awesome! I saw the android dev blog post included this snippet on line height and stuff. I'm going to make a build of this for my design team to look at and hopefully this gets us closer to Figma <> Android "translations" being a bit more 1:1 Thanks SIYAMED (and everyone else that worked on it!)
πŸ‘ 1
g
@Siyamed Thanks for work on this feature πŸ‘ But recently we found strange problem with our custom (developed by 3rd party company) font and includeFontPadding=false and trying to find solution for it. Essentially it looks that our font is not centred properly with LineHeightStyle.Alignment.Center, it a bit off center, everything is fine with default system font. We experimented with different alignment, and it looks mostly fine with Top and Bottom, but not center. Maybe it wouldn’t be a problem for us if we could specify custom Alignment value just for our font, but it’s private constructor (so we cannot emulate behaviour how I saw on your sample app with line distribution Not sure where and how I should report it, maybe just create an issue, or we missing something obvious, but it’s just harder to reproduce because it particular example of font (with which we already had some issues before) This how it looks: UPD: I checked font in font editing application, and our font indeed higher, looks that capital letters fill whole line height, but it still not clear for me why it aligned by compose a bit higher than it should (so it looks that baseline is actually higher than I would like it to be)
πŸ€” 1
βž• 1
Also this how it looks comparing with Figma, the same font, but looks that when line height is higher than font size alignment is off in Compose (the same problem as above, it’s a bit higher than I would expect and comparing it to Figma)
c
Could you share the code behind please? That would help (both Text setup and TextStyle)
g
Yep, sure, give me a few minutes
Copy code
Text(
    text = "BandLab lets you make and share music",
    color = Color.Black,
    style = TextStyle(
        fontSize = 12.sp,
        lineHeight = 16.sp,
        fontWeight = FontWeight.Medium,
        fontFamily = null, // custom font family here
        platformStyle = PlatformTextStyle(
            paragraphStyle = PlatformParagraphStyle(includeFontPadding = false),
            spanStyle = null
        ),
        lineHeightStyle = LineHeightStyle(
            alignment = LineHeightStyle.Alignment.Center,
            trim = LineHeightStyle.Trim.None
        )
    ),
)
s
I can guess based on: The top version looks clipped (20 Feb) whereas the bottom is not. The clipped portion of the top version is the reason why center looks off. This tells me possibly the font ascent is not set according to the characters displayed (and therefore the expectation). Please note that it doesnt mean that the ascent is wrong but the design of the font does not satisfy the expectation. The command of: center only the visible characters requires height of the displayed characters and that is not what lineheightstyle does (nor includeFontPadding). They use ascent and deacent values from the font. We want to add a method/config of layout using tight bounds of characters (css had new configs for similar needs, i forgot the name of the attributes) I guess that this would be font related but in either case a ticket that includes information about the used font would be very useful to double check. Hopefully the font is not paid :/ so that we can check.
g
Hopefully the font is not paid
It is, but I can share it privately, because we are owners of the font
This tells me possibly the font ascent is not set according to the characters displayed
But what I see is that baseline is actually higher than I expecting (you can compare with default font), so it’s not only caused by general font appearance Cannot comment about ascent/descent values which cause problem. Can I somehow check it?
c
Just a wild guess: Can you try to swap Text for BasicText? Material Design tends to change the alignment
g
The top version looks clipped (20 Feb) whereas the bottom is not
it’s indeed a problem by itself, with clipping, but it reproducible only because top line there, for example if I add Γ… to top line it looks fine, but on date line it looks cropped. But what is really a problem for me is baseline alignment, cropping is not a problem on practice for us because line height is larger than font size (~1.3)
About ascent/descent, this how capital characters looks in FontForge, so A fits’ full line as I understand and ring is higher
Just a wild guess: Can you try to swap Text for BasicText
@Can Nope, no difference
c
Just got to read this which came out recently. really cool. good job compose text team! https://medium.com/androiddevelopers/fixing-font-padding-in-compose-text-768cd232425b
❀️ 1
@Siyamed I'm trying to find the blog post that was posted about a month before this one ^ related to text/font padding, but my google fu is failing me. please let me know if you have it handy. cheers! It should have been posted around mid-May.
s
πŸ‘ @Ale Stamato
πŸ™ 1
πŸ’― 1
I'm trying to find the blog post that was posted about a month before this one ^ related to text/font padding,
I couldnt remember which one you had in mind.
I know Can had a post
I dont think google created one, but maybe my brain is failing me
c
Nope. It was a different one that first taught me about this snippet. as you can see. i posted about 2 months ago.
oh well. i suppose it wasn't that important. hate when i cant find something again. πŸ˜‚
c
AHA. Yes! ❀️ ❀️ ❀️