'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()
}
}
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
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 |