< How to create a custom layout using the Layout protocol | How to create stacks using VStack and HStack > |
Updated for Xcode 14.2
New in iOS 16
SwiftUI gives us ViewThatFits
so that we can have it select from one of several possible layouts based on what fits into the available screen space. This makes it a fantastic way to make sure your app looks great from the largest tvOS screen down to the smallest Apple Watch.
In its simplest form, you should list all the layout alternatives you want from most preferred to least preferred, and SwiftUI will try them all until it finds one that fits into the space:
ViewThatFits {
Label("Welcome to AwesomeApp", systemImage: "bolt.shield")
.font(.largeTitle)
Label("Welcome", systemImage: "bolt.shield")
.font(.largeTitle)
Label("Welcome", systemImage: "bolt.shield")
}
Download this as an Xcode project
That attempts a long title in large text, a short title in large text, then finally a short title in small text – SwiftUI will try them in that order, and stop as soon as one fits into the available space.
This is particularly useful when you’re working with views that can be arranged vertically or horizontally depending on space. For example, this creates a view with four different buttons, then decides to arrange them horizontally or vertically depending on how much space there is:
struct OptionsView: View {
var body: some View {
Button("Log in") { }
.buttonStyle(.borderedProminent)
Button("Create Account") { }
.buttonStyle(.bordered)
Button("Settings") { }
.buttonStyle(.bordered)
Spacer().frame(width: 50, height: 50)
Button("Need Help?") { }
}
}
struct ContentView: View {
var body: some View {
ViewThatFits {
HStack(content: OptionsView.init)
VStack(content: OptionsView.init)
}
}
}
Download this as an Xcode project
Where things get more interesting is how ViewThatFits
handles handles text layout. Text in SwiftUI prefers to sit on one line, and by default ViewThatFits
will prefer to avoid layouts the cause text to wrap. So, when space is limited code like this will default to a VStack
rather than use a HStack
with wrapping text:
ViewThatFits {
HStack {
Text("The rain")
Text("in Spain")
Text("falls mainly")
Text("on the Spaniards")
}
VStack {
Text("The rain")
Text("in Spain")
Text("falls mainly")
Text("on the Spaniards")
}
}
.font(.title)
Download this as an Xcode project
What’s happening here is that ViewThatFits
is measuring our text both horizontally and vertically, and is trying to find something that fits the text in both those dimensions – something where the text fits all on one line, without being truncated vertically.
This sometimes causes problems, but fortunately we can tell ViewThatFits
to care about only one dimension so that we can get more control.
For example, say you wanted to display some terms and conditions to the user, and have it as fixed text if it can be fitted into the space, but scrolling text otherwise. This kind of code won’t work as you expect:
struct ContentView: View {
let terms = String(repeating: "abcde ", count: 100)
var body: some View {
ViewThatFits {
Text(terms)
ScrollView {
Text(terms)
}
}
}
}
Download this as an Xcode project
Unless you have a huge screen, that will always choose the scrolling version because we asked ViewThatFits
to care about both horizontal and vertical axes for our text. This means as soon as the text runs across more than one line, SwiftUI will prefer to avoid that layout.
To fix this we need to restrict ViewThatFits
to measure only the vertical axis, like this:
struct ContentView: View {
let terms = String(repeating: "abcde ", count: 100)
var body: some View {
ViewThatFits(in: .vertical) {
Text(terms)
ScrollView {
Text(terms)
}
}
}
}
Download this as an Xcode project
Now that will allow the text to wrap horizontally, but as soon as it runs out of vertical space SwiftUI will move on to the ScrollView
.
SAVE 50% To celebrate WWDC23, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
Link copied to your pasteboard.