115

Even After setting the .lineLimit(nil) the text doesn't get wrapped.

var body: some View {
    VStack(alignment: .center) {
        Text("SwiftUI is a modern way to declare user interfaces for any Apple platform. ")
            .font(.title)
            .color(.red)
            .lineLimit(nil)
        Text("Create beautiful, dynamic apps faster than ever before.")
            .font(.system(size: 20))
            .lineLimit(nil)
    }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
}

enter image description here

NebulaFox
  • 7,813
  • 9
  • 47
  • 65
Let's_Create
  • 2,963
  • 3
  • 14
  • 33

10 Answers10

315

After spending a lot of time with an error like this, I can't be 100% certain that this is a lineLimit issue. As of writing this post, the solution I found with more complex views is the following snippet of code to prevent wrapping:

.fixedSize(horizontal: false, vertical: true)

This should prevent the interpreter from collapsing text vertically.

starball
  • 20,030
  • 7
  • 43
  • 238
Sharpienero
  • 3,264
  • 2
  • 11
  • 7
  • 3
    This solution fixed my issue after trying lineLimit and removing Spacer() – Jaron Gao Dec 12 '19 at 15:02
  • 1
    @JaronGao This should also work with a `Spacer()`, unless I am misconstruing what you are saying. Either way, I am glad I was able to help! – Sharpienero Dec 13 '19 at 17:39
  • Oh, I meant this solution worked independently after trying the lineLimit fix and the "remove Spacer()" fix. – Jaron Gao Dec 13 '19 at 20:36
  • None of the other solutions worked for me but this one worked for me. Thanks! :) – Luke Chambers Dec 14 '19 at 01:21
  • What's particularly weird about this solution is that in my case the text doesn't even NEED to wrap. Before adding this the text was cropped, after it shows fine on one line – lewis Sep 28 '20 at 14:48
  • 6
    Beware though that "This can result in the view exceeding the parent's bounds, which may or may not be the effect you want." – Zsolt Nov 26 '20 at 12:31
  • A great tip which solved my issue in a complex view with `GeometryReader` and a `VStack` with artificial frame width 3 times the original width. But interestingly I use two times `false` `fixedSize(horizontal: false, vertical: false)` and it works... I do not understand `fixedSize`, it seems. – pd95 Nov 30 '20 at 14:07
  • 1
    On macOS this modifier resizes window. The window after that not even fits the screen :0 – Vlad Mar 21 '21 at 17:35
  • This also fixed the issue for me, whereas `linelimit` had no effect on either the text view or the parent view – Indiana Jul 29 '21 at 10:16
  • This should be the correct answer! Works like a charm! – SchmidtFx Feb 08 '22 at 10:15
  • I still think Apple should give a look into this. This can't be a definitive solution because when you apply it, the text overflows the parent, when the desired behavior is for the parent to grow as much as the text needs. – Tiago Peres França Aug 19 '22 at 19:21
  • This solution perfect worked and save my time, thanx @Sharpienero – Digvijaysinh Gida Nov 08 '22 at 06:37
  • As others have pointed out, this stretches the window to the max on macOS. The only other way I've found to wrap the text is to set a fixed frame height, which I'd prefer not to have. Amazing there isn't another way. – Ricky Kresslein Feb 12 '23 at 11:22
  • Yep this works like a charm. – Amey079 Jun 14 '23 at 15:53
  • Yes, works here too. I find it REALLY irritating what SwiftUI is doing here... This should be simple. – soundflix Jun 25 '23 at 15:10
41

The full solution as of Xcode 11.3 / Swift 5.1 is found across multiple answers here.

The explanation for why this is happening is found in Matteo Pacini's answer: using the predefined .font(.title), .font(.headline), etc. seems to bring the behavior that these Text views will size themselves to always ellipsize rather than wrap. However, simply switching to .body doesn't seem like the best work around.

The best workaround is found in Sharpienero's answer: add .fixedSize(horizontal: false, vertical: true) to your Text view. This tells the Text view to NOT do its custom re-sizing horizontal logic of NOT ellipsizing which causes it to follow the standard rules that we're all use to.

Thanks to both of them!

awolf
  • 1,862
  • 22
  • 29
  • 3
    Hey, thank you for the additional information. I do feel as if my answer is lacking, so this is a good supplemental answer. Thanks again! – Sharpienero Feb 12 '20 at 19:09
31

Try changing the second Text's lineLimit to a number instead of nil:

VStack(alignment: .leading) {
  Text("SwiftUI is a modern way to declare user interfaces for any Apple platform. ")
    .font(.title)
    .color(.red)
    .lineLimit(nil)
  Text("Create beautiful, dynamic apps faster than ever before.")
    .font(.system(size: 20))
    .lineLimit(2)
 }.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))

Result:

enter image description here

M Reza
  • 18,350
  • 14
  • 66
  • 71
  • It certainly works but how did reach this solution. – Let's_Create Jun 08 '19 at 11:51
  • @Let's_Create Text type is acting strange here! For example if you swap the two Text both having lineLimit(nil) it works as expected. Or if you remove the title font it works again. I'm really not sure about this behavior since it's still in beta phase. – M Reza Jun 08 '19 at 12:31
  • This does not work for me in Beta 2. The only way I could get it to work is by adding `.lineLimit(3)` to the VStack (which causes it to apply to all children). It seems like `.lineLimit(nil)` just has no effect, and `lineLimit` must be added to a parent, not the `Text` views directly – Benjamin Kindle Jun 22 '19 at 15:57
  • @BenjaminKindle Thanks for your workaround. It should normally work with both having `lineLimit(nil)` but it's behaving very unstable in beta phase that changing a font also fixes this! – M Reza Jun 22 '19 at 16:13
  • 5
    I tried this, and setting both to `99999`, but I see no change. – Ky - Feb 06 '20 at 23:56
  • Setting lineLimit(nil) was not helpful. This worked instead: `.fixedSize(horizontal: false, vertical: true)` – P. Ent Apr 22 '20 at 16:51
  • lineLimit seems like it is related only to the numbers of lines based on counting the embedded newlines. Multi-line text with newlines causes the matching number of lines to be used for the Text view. Once that is established, if you resize the gui (on mac for instance) you can see that the text does wrap. But the total lines of the view doesn't change. – Chris Quenelle May 17 '20 at 03:14
  • By using `.fixedSize(horizontal: false, vertical: true)` I was able to get the Text itself to dynamically size to multiple lines (given one long line as the string), but the parent view still assumed it was one line. So the Text view expanded beyond it's allocated space and got truncated on the edges. So far it seems consistently broken in Xcode 11.4.1. Line wrapping does not affect the surrounding geometry in any way from what I can see. – Chris Quenelle May 17 '20 at 03:24
  • Ooops. Now I think my problem might have been that my text was inside a List. If I do the same thing in a blank app, it works differently. – Chris Quenelle May 17 '20 at 03:33
  • As it turns out I didn't need the call to fixedSize. Once I moved my text out of the List view and input an HStack instead, it started resizing itself dynamically the way I wanted. I would nornally want to delete all my comments above, except I think it's important to note that the docs for lineLimit() don't really explain much. The number of lines in some cases seems dictated by the number of newlines in the string, even when lines are wrapping. – Chris Quenelle May 17 '20 at 04:05
13

It looks like the font holds line wrapping attributes.

If you change it to body, then it wraps correctly!

enter image description here

Matteo Pacini
  • 21,796
  • 7
  • 67
  • 74
8

For my problem, I had a setup like this:

public var body: some View {
    Form {
        Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
            .font(.title)

        Spacer()
            .fixedSize()

        Text("""
            Integer ut orci odio. Proin cursus ut elit eget rutrum. Nunc ante sem, euismod sed purus sed, tempus elementum elit. Phasellus lobortis at arcu quis porta. Cras accumsan leo eu tempus molestie. Suspendisse vulputate diam ipsum, et tristique lorem porta et. Pellentesque sodales est id arcu luctus venenatis.

            Vestibulum non magna lorem. In tincidunt aliquet nunc, sit amet pharetra neque hendrerit id.

            Cras sed!
            """)

        NativeButton("OK", keyEquivalent: .return) { self.screen = .game }
    }
        .frame(maxWidth: 480)
        .fixedSize()
        .padding()
}

Only the first line of the first `Text` and the first few lines of the second `Text` appear

For some reason, all I had to do was add minWidth: 480, idealWidth: 480 to the frame and everything rendered correctly. I didn't expect this because I already applied .fixedSize(), so I figured one of these three should've been enough.

public var body: some View {
    Form {
        Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
            .font(.title)

        Spacer()
            .fixedSize()

        Text("""
            Integer ut orci odio. Proin cursus ut elit eget rutrum. Nunc ante sem, euismod sed purus sed, tempus elementum elit. Phasellus lobortis at arcu quis porta. Cras accumsan leo eu tempus molestie. Suspendisse vulputate diam ipsum, et tristique lorem porta et. Pellentesque sodales est id arcu luctus venenatis.

            Vestibulum non magna lorem. In tincidunt aliquet nunc, sit amet pharetra neque hendrerit id.

            Cras sed!
            """)

        NativeButton("OK", keyEquivalent: .return) { self.screen = .game }
    }
        .frame(minWidth: 480, idealWidth: 480, maxWidth: 480)
        .fixedSize()
        .padding()
}

All the text appears as intended

Ky -
  • 30,724
  • 51
  • 192
  • 308
4

SwiftUI

.lineLimit(nil) VS .lineLimit(any number)

VStack(alignment: .leading, spacing: 16.0) {
// Sets the maximum number of lines that text can occupy in the view.

      Text("SwiftUI is a user interface toolkit that lets us design apps in a declarative way. ")
      .font(.title)
      .lineLimit(3)

// But if you don't know about the the text size then Sets nil in the lineLimit.

      Text("SwiftUI is a user interface toolkit that lets us design apps in a declarative way. That's a fancy way of saying that we tell SwiftUI how we want our UI to look and work, and it figures out how to make that happen as the user interacts with it.... ")
       .font(.body)
       .lineLimit(nil)
}.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8))
Akbar Khan
  • 2,215
  • 19
  • 27
1

I had a situation involving a UIViewRepresentable wrapped UITextField which was presented as:

VStack {
    Text("Long enough to wrap....")
    Spacer().frame(height: 40)
    CustomTextField()
}

The Text stopped wrapping when I added the CustomTextField. Nothing I did to the Text helped. If I removed the Spacer() it wrapped just fine!!

I wound up removing the Spacer and adding a bottom padding to the Text. As far as I can tell, my CustomTextField is just fine and I cannot see why it would affect the SwiftUI layout algorithms.

P. Ent
  • 1,654
  • 1
  • 12
  • 22
0

I just added

.padding()

to my Text instance and it worked

J. Doe
  • 12,159
  • 9
  • 60
  • 114
0

The only answer that kinda worked for me was applying .fixedSize(horizontal: false, vertical: true) on the Text.

I say "kinda" because, by using .fixedSize, SwiftUI will completely ignore the size given by the parent and overflow it. If the parent has a background, the layout is ruined. If the parent has a sibling node, the text is rendered on top of it.

I really believe Apple should give us the option to have the ideal size of a Text be its multiline version instead of the one-line counterpart.

While this doesn't happen, I'm using the following monstrosity, but it works:

struct AdaptiveText: View {
  @State private var height: CGFloat?
  var text: String
  
  private func updateHeight(height: CGFloat) -> some View {
    DispatchQueue.main.async {
      self.height = height
    }
    return Color.clear
  }
  
  var body: some View {
    ZStack {
      Text(text)
        .fixedSize(horizontal: false, vertical: true)
        .background() {
          GeometryReader { geo in
            updateHeight(height: geo.size.height)
          }
        }
        .opacity(0)
      
      Text(text)
    }.frame(width: nil, height: height)
  }
}
Tiago Peres França
  • 3,056
  • 2
  • 21
  • 23
0

I've just set maxWidth to the outer ContentView — now text wraps. Didn't do anything with Text props.

  var body: some Scene {
    WindowGroup {
      ContentView().frame(maxWidth: 300)
    }
  }
Vladimir Tolstikov
  • 2,463
  • 21
  • 14