Search code examples
iosswiftswiftuiswiftui-text

SwiftUI Text scaledToFit and wrap text


I have a button with dynamic text. I'm looking to scale the text down to fit it (as much as possible), and wrap the text to some number of lines (probably 2?).

By default, SwiftUI appears to wrap the text on words. But it seems like when I use the scaledToFit modifier on my Text view, it prevents the words from wrapping.

Here is some playground code to illustrate:

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
  var body: some View {

    let lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

    VStack {

      // Here is the default text - see in the screenshot that it properly wraps the text
      HStack {
        Text(lorem)
      }
      .frame(width: 100, height: 100)
      .background(Color.blue)

      // Here is text that is scaled down, but prevented from wrapping, even though 
      // we have allowed it to use 2 lines.
      HStack {
        Text(lorem)
          .allowsTightening(true)
          .scaledToFit()
          .lineLimit(2)
          .minimumScaleFactor(0.7)
      }
      .frame(width: 100, height: 100)
      .background(Color.green)

      // Here is the text with the same scaling modifiers as above, but it
      // is still set to the original font size
      HStack {
        Text("Short")
          .allowsTightening(true)
          .scaledToFit()
          .lineLimit(2)
          .minimumScaleFactor(0.7)
      }
      .frame(width: 100, height: 100)
      .background(Color.pink)

    }
  }
}

PlaygroundPage.current.setLiveView(ContentView())

Screenshot of playground result

So, ideally, I'd like a combination of the first and second views - I would like the text to wrap, but also shrink to some minimum size if the text doesn't immediately fit in the parent view.


Solution

  • try this, and similarly for the pink:

        HStack {
            Text(lorem)
                .frame(width: 100, height: 100)  // <--- here
                .allowsTightening(true)
                .lineLimit(2)
                .scaledToFit()
                .minimumScaleFactor(0.7)
        }
        .frame(width: 100, height: 100)
        .background(Color.green)