I'm trying to code a simple login page on my app. I started using SwiftUI on my newly updated macOS Catalina. The Apple documentation is still lacking a lot. I need to center a VStack vertically on a Scrollview occupying the whole page with a "limit" on it's width of 400.
Something like this:
ScrollView(.vertical) {
VStack {
Text("Hello World")
}
.frame(maxWidth: 400, alignment: .center)
}
It was easy with UIScrollView, just needed to set the ContentView to fill height and width and then centering a Vertical StackLayout inside the Content View but now with SwiftUI I just wonder.
The goal is something like this (Credit to the author)
If someone is wondering why I want everything inside a scrollview, it's because my form is quite big and I expect the user to use both landscape and portrait view so I really need the content to be scrollable. Bear in mind also that in an iPad, the form doesn't fill the whole screen, that's why I want it centered vertically.
As of iOS 17, you can achieve this without a GeometryReader
by using containerRelativeFrame
to reserve space in a ZStack
.
As a bonus you can also disable scroll bouncing with .scrollBounceBehavior(.basedOnSize)
.
ScrollView {
ZStack {
// Reserve space matching the scroll view's frame
Spacer().containerRelativeFrame([.horizontal, .vertical])
// Form content
VStack {
Text("Form goes here")
}
// Set your max width (optional)
.frame(maxWidth: 400)
.padding()
.background(Color.yellow)
}
}
// Disable bounce if the content fits (optional)
.scrollBounceBehavior(.basedOnSize)
You can vertically center content in a scroll view by using GeometryReader
to get the parent view's dimensions and setting the scroll view's content's minHeight
to the parent's height.
When the content is too big to fit vertically it'll just scroll like normal.
For example:
var body: some View {
GeometryReader { geometry in
ScrollView(.vertical) {
// Form content
VStack {
Text("Form goes here")
}
// Set your max width (optional)
.frame(maxWidth: 400)
.padding()
.background(Color.yellow)
// Make the scroll view full-width
.frame(width: geometry.size.width)
// Set the content’s min height to the parent
.frame(minHeight: geometry.size.height)
}
}
}