
Dynamically adapting to available space with ViewThatFits
Learn how to create views that adapt their size in order to fill the available space on the UI with SwiftUI.
ViewThatFits
is a SwiftUI component introduced from iOS 16 that allows your view to become responsive according to the available space that will contain it.
By providing a series of possible views to display - ordered by preference, the component will use the @ViewBuilder
to build the first one that fits the space available.
This is very useful when the parent’s container size is not fixed and you want the child view to adapt based on that size.
ViewThatFits(in: .vertical) {
//First Option
VStack {
Image(systemName: "swift")
.imageScale(.large)
.foregroundStyle(.tint)
Text("We can’t wait to see what you will Create with Swift.")
}
.font(.system(size: 45))
.fontWeight(.ultraLight)
.frame(width: 350, height: 350)
//Second Option
Text("Create with Swift")
.font(.system(size: 45))
.fontWeight(.ultraLight)
//Third Option
Text("Swift")
.font(.system(size: 40))
.fontWeight(.ultraLight)
//Fourth Option
Image(systemName: "swift")
.foregroundStyle(.tint)
.font(.system(size: 40))
}
To begin using ViewThatFits
, declare an instance of the component. It takes two parameters:
- The axis used to fill. By default, it uses both axes, while if specified, it chooses the first child whose size fits within the proposed size on that axis;
- The content is to be displayed in the view.
In the example above, ViewThatFits
works on the vertical axis and takes four different views ordered by preference.
Integrated with the parent view, it will look like this:
import SwiftUI
struct ContentView: View {
@State private var frameSize: CGFloat = 350
@State private var isEditing = false
var body: some View {
VStack {
Spacer()
VStack {
ViewThatFits(in: .vertical) {
//First Option
VStack {
Image(systemName: "swift")
.imageScale(.large)
.foregroundStyle(.tint)
Text("We can’t wait to see what you will Create with Swift.")
}
.font(.system(size: 45))
//Second Option
Text("Create with Swift")
.font(.system(size: 45))
//Third Option
Text("Swift")
//Fourth Option
Image(systemName: "swift")
.foregroundStyle(.tint)
}
}
.fontWeight(.ultraLight)
.font(.system(size: 40))
.frame(width: frameSize, height: frameSize)
.overlay {
RoundedRectangle(cornerSize: CGSize(width: 12, height: 12))
.stroke(Color.blue, lineWidth: 1)
}
Spacer()
Slider(value: $frameSize, in: 60...350) { isEditing in
self.isEditing = isEditing
}
Text("Frame size: \(Int(frameSize))")
}
.padding()
}
}
This SwiftUI view dynamically adjusts a ViewThatFits
container with fourth layouts: an icon and text, just text in 2 different versions, or just an icon, based on the frame size controlled by a slider. A blue-bordered square resizes with the slider, showcasing how the layout adapts. The current size is displayed below the slider for reference.
As you can see, ViewThatFits
allows to have control on how your view is adapting based on the changing in size of the container that will contains it, making it ideal for adaptable UIs where container sizes vary.