Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set line height for a single line text in SwiftUI?

Currently, I have been using .lineSpacing(...), but this only works for multi-line text.

/// Sets the amount of space between lines of text in this view.
///
/// - Parameter lineSpacing: The amount of space between the bottom of one
///   line and the top of the next line.
@inlinable public func lineSpacing(_ lineSpacing: CGFloat) -> some View

What this means is that it's harder for me to translate fonts exactly from sketch/figma, and I need to play around with the padding to get it right. Here is an example that shows this:

VStack {
    // Line spacing is ignored.
    Text("Hello, World!")
        .background(Color.green)
        .lineSpacing(50)

    Spacer()

    // Line spacing is correct.
    Text("Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups.")
        .background(Color.green)
        .lineSpacing(50)
}
like image 223
Zorayr Avatar asked May 09 '20 23:05

Zorayr


2 Answers

Based on the answer by Dan Hassan I made myself a ViewModifier to do this, and it looks like it works as intended

import SwiftUI

struct FontWithLineHeight: ViewModifier {
    let font: UIFont
    let lineHeight: CGFloat

    func body(content: Content) -> some View {
        content
            .font(Font(font))
            .lineSpacing(lineHeight - font.lineHeight)
            .padding(.vertical, (lineHeight - font.lineHeight) / 2)
    }
}

extension View {
    func fontWithLineHeight(font: UIFont, lineHeight: CGFloat) -> some View {
        ModifiedContent(content: self, modifier: FontWithLineHeight(font: font, lineHeight: lineHeight))
    }
}
like image 178
Ole-Kristian Avatar answered Oct 20 '22 14:10

Ole-Kristian


For getting your text to match figma here's what finally worked for me. If for example your figma designs had a particular font of 16 pt with a line height of 32 pt:

let font = UIFont(name: "SomeFont", size: 16)!
return Text("Some Text")
    .font(.custom("SomeFont", size: 16))
    .lineSpacing(32 - font.lineHeight)
    .padding(.vertical, (32 - font.lineHeight) / 2)

In order to get the exact line spacing value we have to subtract our desired line height by the font's inherent line height but as you noted this will only take effect on multiline text and only between lines. We still need to account for the top and bottom padding of the text to match the desired line height so once again add the total line height minus the font's line height.

like image 45
Dan Hassan Avatar answered Oct 20 '22 13:10

Dan Hassan