Reducing Line Spacing of Text in SwiftUI

7k views Asked by At

For some fonts, the built-in line spacing is unpleasantly large.

SwiftUI gives us the Text modifier .lineSpacing() to adjust the spacing between lines of text (also called the leading, unrelated to leading/trailing). Its value specifies the number of points of additional spacing to place between consecutive lines of text, so that .lineSpacing(0) results in no change. Unfortunately, it does not appear to respond to negative values; .lineSpacing(-10) yields the same result as lineSpacing(0).

Does anyone know of a way to reduce line spacing in SwiftUI without resorting to UIKit?

6

There are 6 answers

0
Alex Fringes On BEST ANSWER

While I don't think it's possible to gain free control over negative line spacing in SwiftUI atm — as of Fall '22 all negative values create the same, only marginally tighter leading, no matter the value — you can reduce the leading of the Font itself, by applying .leading(.tight) to the Font. This did tighten a quick test example beyond what the negative value cap of .lineSpacing(-X) seems to achieve.

0
Sadman Adib On

You can use '\n' to denote line breaks and use the following:

struct CustomTextView: View {
  var text: String
  var font: Font
  var lineSpacing: CGFloat

  var body: some View {
    VStack(alignment: .leading, spacing: lineSpacing) {
      ForEach(text.components(separatedBy: "\n"), id: \.self) { line in
        Text(line)
          .font(font)
      }
    }
  }
}
1
Ribi On

I think it works using negative values in some way.

Example

First image has lineSpacing set to -3, second set to 0.

-3 is the less value where I can see some effects.

2
AudioBubble On

You can split up the text in multiple lines and apply negative padding around each one like this:

Text("This is the first Line")
    .padding(-10)
Text("This is the second Line")
    .padding(-10)
1
Larry Mickie On

Introduced in iOS 17 there's an Environment modifyier that you use to increase/decrease line spacing:

MyView()
.environment(\._lineHeightMultiple, 0.9) 

Not sure if its a 100% public API but it does the job.

2
kobuchi On

EDIT: Unfortunately this stopped working in Xcode 15 as the function is now marked internal and there is no other option available. Damn Apple!


Based on tadelv comment.

lineSpacing does not accept negative values, but you have a hidden API _lineHeightMultiple that works. It says it's deprecated but the suggested one does not exist!

var body: some View {
  let font = UIFont.systemFont(ofSize: 12)
  let fontLineHeight = font.lineHeight
  let desiredLineHeight = 24.0

  Text("text")
    .font(Font(font))
    ._lineHeightMultiple(desiredLineHeight / fontLineHeight)
}

Remember that using private apis could be rejected by App Store Review or break on future ios versions. Use at your own risk! (Damn Apple!)