'SwiftUI Word Wrap for multiline text Word Hyphenation Problem

I'm facing the following problem with SwiftUI Text: In the following example SwiftUI breaks the word "Amazement" into "amazeme" on the first line and "nt" on the second. How to avoid it, isn't it a bug?

I want the word "amazement" to be written on one line. Is there any modifier that can allow this (don't divide words or something)?

Tried .allowsTightening, .fixedSize. Changed the order of modifiers, Didn't help.

Is it a bug or we currently don't have an option to fix this? The solution should work for every String, not only for the mentioned string.

You can replicate the behaviour using this code:

 struct TestView2: View {
    var body: some View {
        ZStack {
        Text("Amazement Awaits us at every corner")
           
            .font(.system(size: 160))
            .foregroundColor(.blue)
            .foregroundColor(.white)
            .lineLimit(4)
            .multilineTextAlignment(.leading)
            .minimumScaleFactor(0.01)
            //.allowsTightening(true)
            //.fixedSize(horizontal: false, vertical: true)
      
        }
    }
}
    
    struct TestView2_Previews: PreviewProvider {
        static var previews: some View {
            TestView2()
        }
    }

Example of Text hyphenation problem



Solution 1:[1]

Looks like wrapping words by character is the default when it comes to fitting text in a view. I found that .minimumScaleFactor only works if the system is not able to fit the text (with character breaks). If that didn't work then it will try to scale the text down. If you try to decrease the linelimit then minimumScaleFactor will kick in and try to make the text smaller until it fits.

At the moment I'm using a hack where I check the number of characters of words in the text, if any word has more characters than a certain threshold then I decrease the font size, otherwise I use the default size.

struct TestView2: View {
    let text: String
    var body: some View {
        ZStack {
            Text(self.text)
                .font(.system(size: self.getSizeForText(self.text)))
                .foregroundColor(.blue)
                .foregroundColor(.white)
            .lineLimit(4)
            .multilineTextAlignment(.leading)
            .minimumScaleFactor(0.01)
            //.allowsTightening(true)
            //.fixedSize(horizontal: false, vertical: true)
        }
    }
    
    private fund getSizeForText(_ text: String) -> Double {
        let CHARS_THRESHOLD = 12 // change this as needed
        let words = text.split(separator: " ")
        if words.contains(where: { $0.count > CHARS_THRESHOLD }) {
            // text contains a long word, decrease the font size
            return 150.0 // the smaller size, change as needed
        }
        // all words are shorter than the threshold
        return 160.0 // the default size, change as needed
    }
}

This won't work for all scenarios, but hopefully it's tweakable until Apple comes up with a proper solution to this as I can't imagine a scenario where breaking words by character without even a hyphen is the best solution.

Solution 2:[2]

FIXED: Xcode 13.3 / iOS 15.4

demo

Text("Amazement Awaits us at every corner")

    .font(.system(size: 460))   // << even such size (or any other big)
    .foregroundColor(.blue)
    .foregroundColor(.white)
    .lineLimit(4)
    .multilineTextAlignment(.leading)
    .minimumScaleFactor(0.01)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mota
Solution 2 Asperi