SwiftUI Text: line height of 1st line ≠ HIG text style - why ?

[this is a copy with new 'SwiftUI' tag of a - still unanswered - questions with 'WWDC20' & 'UI Frameworks' tags - there seem to be no way to add tags after posting ...?]


So here it goes:


The line height of the 1st line of a SwiftUI Text view is different from what the HIG specifies:

For example (Content Size Category = .large , @2) :
(Please see code below)

  • 10 lines of Body - HIG             =  220.00 pt

  • 10 lines of Text with Body         =  218.50 pt

  • 10 x 1 lines of Text with Body   =  205.00 pt


The difference depends on Content Size Category and resolution of the device.

Behavior is the same in Xcode 11 (macOS 10.15.5) and Xcode-beta 12 (macOS 11.0 Beta (20A4299v))


Questions:
Why is that?
What’s the benefit of that?
Is there an easy way to specify HIG line heights - so that the frame size of the Text is a clean multiple of HIG's line height?


Thanks!



Code Block Swift
import SwiftUI
struct LineHeights: View {
var body: some View {
HStack(alignment: .top, spacing: 0) {
//  1x10 lines in "L Body" - height = 218.50 pt - why?
//  =======================================================
Text("Hello, World! 0\nHello, World! 1\nHello, World! 2\nHello, World! 3\nHello, World! 4\nHello, World! 5\nHello, World! 6\nHello, World! 7\nHello, World! 8\nHello, World! 9")
.frame(width:120)
.overlay(Measurement(color: .green))  //  reads:  218.50pt  (@3: 218.33pt)
//  10x1 lines in style "L Body" - height = 205.00 - why?
//  =======================================================
VStack(spacing: 0) {
Text("Hello, World! 0")
Text("Hello, World! 1")
Text("Hello, World! 2")
Text("Hello, World! 3")
Text("Hello, World! 4")
Text("Hello, World! 5")
Text("Hello, World! 6")
Text("Hello, World! 7")
Text("Hello, World! 8")
Text("Hello, World! 9")
}
.frame(width:120)
.overlay(Measurement(color: .yellow))  //  reads:  205.00pt (@3: 203.33pt)
//  Apple HIG:  10 lines in "L Body" - height = 220 pt
//  =====================================================
Text("Apple iOS HIG:\n10 x Body = 220 pt")
.font(.caption)
.frame(width:120, height: 220)
.overlay(Measurement(color: .blue))  //  reads:  220.00pt  (@3: 220.00pt)
}
}
}
struct Measurement: View {
let color: Color
var body: some View {
//  measure
GeometryReader {
geometry in
ZStack(alignment: .bottomTrailing) {
//  color
self.color.opacity(0.8)
//  display
measurementText("\(geometry.size.height, specifier: "%.2f")")
.font(.title2).fontWeight(.bold)
.foregroundColor(.red)
}
}
}
}
struct LineHeights_Previews: PreviewProvider {
static var previews: some View {
LineHeights()
}
}


(I'm struggling with reformatting the source code - so apologies if it looks scrambled - the original post (with same title) is OK)



The results are expected.

The 22 pt value reported by HIG is the value with line height plus leading.

Each line using body font would have a default line height of 20.287, plus leading it would be 22 pt exactly.

When you have a single line, the leading is not applied, it is only applied between lines , that’s why a Text with 10 lines would have a height of 22 * 9 + 20.287 = 218.287. SwiftUI will round the height to scale (in a 2X resolution it would be rounded to 0.5 pt since that is a whole pixel.) so you get 218.5 pt.

When you have 10 single line Text, since leading is not applied, each line height is 20.287, rounded to 20.5 pt by SwiftUI, so you ended up with a total height of 205 pt.

Many thanks for your explanations! - Understood.


May I add some more questions? :

  • Is there an easier way (ie. without UIKit) of achieving HIG line height than

Code Block Swift
Text("Hello, World!")
.padding(.top, UIFont.preferredFont(forTextStyle: .body).leading)

  • What am I not getting - why is not everyone complaining - what is the benefit of having Text behave that way?


Thanks!



Because leadings are by definition the spacing between lines. It doesn’t make sense to leave a leading at the last line of a Text view. This behavior is also consistent with other UI frameworks. What HIG describes is the spacing between baselines.

Thanks again!!

OK, I understand that by definition leading is only between lines.



Please let me rephrase my central question with an example:

iOS Mail in its list of mails uses the following format:


Sender

Subject
1st text line ...
2nd text line ...


The baseline of the Subject line and the baseline of the 1st text line are 20pt apart.
The baseline of the 1st text line and the baseline of the 2nd text line are 20pt apart.

The second distance (1st to 2nd text line) is easy to achieve by using the standard line height of eg. .subhead.

How can I achieve the first distance(Subject line to 1st text line)?

Code Block Swift
VStack {
    Text("Subject").font(. subheadline)
        .padding(.bottom, UIFont.preferredFont(forTextStyle: .subheadline).leading / 2) 
    Text("lines of text ... ...").font(. subheadline).foregroundColor(.gray)
        .padding(.top, UIFont.preferredFont(forTextStyle: .subheadline).leading / 2) 
}



Is there something simpler (ie. without using UIKit) ?



Thank you!

Code Block Swift
VStack {


should of course read


Code Block Swift
VStack(..., spacing: 0) {



SwiftUI Text: line height of 1st line ≠ HIG text style - why ?
 
 
Q