davidgagne.net

  • About
  • Archives
  • Twitter
  • Facebook
  • bartender.live
  • GitHub
  • LinkedIn

Dealing with Word Breaks in SwiftUI Text

September 30th, 2020 @ 3:21 pm PDT

What to do when .allowsTightening and .minimumScaleFactor are not cutting it

Dealing with Word Breaks in SwiftUI Text

Note: If you are a SwiftUI developer, you need to get Core Data Mastery from Big Mountain Studio. You'll learn everything you need to take your apps to the next level.

There are at least a half-dozen different ways to deal with font scaling issues in a SwiftUI Text view. It took me quite some time to determine that none of them would cover all of the different scenarios presented by attempting to display variable-length cocktail titles in a small iOS 14 widget for my bartender recipe app.

iOS 14 Cocktail WidgetThis only mattered for me when working with long titles in the .systemSmall size widget. The .systemMedium and .systemLarge widgets both handle word wrapping and scaling properly as far as I’m concerned. And the small widget handles multi-word titles with no problem. But the .systemSmall widget was either truncating (which I didn’t want), word-wrapping in a weird space, or scaling the font so tiny as to be illegible.

AardvarkBananaI don’t want to truncate the text in the small widget, because then it looks like a mistake, so I couldn’t do that. If what I need to display is Purple Monkey Dishwasher there’s no problem, because SwiftUI word wraps Dishwasher to the next line. Setting the .minimumScaleFactor works, but when you actually hit the minimum, you don’t want the text to truncate a single word, which was what was happening. If the text included a single word that was too long — like AardvarkBanana — the word would get displayed in the small widget as AardvarkBana with just na on the next line, which looked idiotic.

So what I wanted was a way to allow for word wrapping for something like Purple Monkey Dishwasher but disallow word wrapping for something like AardvarkBanana.

Using .allowsTightening is a good idea, and setting a .minimumScaleFactor is important.

My solution was to add a function to my struct that will tell my widget entry whether the text is one (potentially really long) word — which I don’t want to break at all — or whether it is more than one word, in which case it’s fine to break it. Then I use the result of that function in the .lineLimit() attribute of my Text view.

struct MyThing {
    let title: String
    …

    func correctLineLimit() -> Int {
        let wordcount = title.split(separator: " ")
        return wordcount.count > 1 ? 2 : 1
    }
}
if widgetFamily == .systemSmall {
        Text(entry.thing.title)
            .font(.title2)
            .bold()
            .lineLimit(entry.thing.correctLineLimit())
            .allowsTightening(true)
            .minimumScaleFactor(0.75)
}

* header image from the excellent AppCoda book Mastering SwiftUI

More posts tagged:
Apple / Programming / swift / xcode

More posts categorized:
Programming technology

More posts from:
September 2020 / 2020

Post navigation

Previous Post
Previous Post On Perspective
Next Post
Next Post Never Forget

Search


Your Cocktail Companion

Your Cocktail Companion

Discover what drinks you can make from the alcohol you have at home and become a first-class mixologist with bartender.live for iOS.

  • Make Beautiful Cocktails

© David Vincent Gagne. All rights reserved. Custom WordPress Theme by Jacket Industries.