In my app, I have a ScrollView
that has one static subview as a header and a LazyVStack
with multiple elements that is filled with data from the view model. Additionally, if this "dynamic" data is empty, instead of the LazyVStack
, I show a placeholder view. Here’s a simplified structure of the view:
var body: some View {
GeometryReader { geometry in
ScrollView {
HStack(spacing: .zero) {
Text("This is my greeting to you")
Spacer()
}
if greetings.isEmpty {
PlaceholderView()
.frame(height: geometry.size.height)
} else {
LazyVStack {
ForEach(greetings, id: .self) {
Text($0)
}
}
}
}
}
}
private var greetings: [String]
PlaceholderView
:
VStack {
Image(systemName: "hand.wave")
Text("Hello world!")
}
I want PlaceholderView
to be displayed in the middle of the available space (i.e., in this case, the entire screen height minus the height of the HStack
on the top.) Many somewhat similar questions here suggest using GeometryReader
, but it doesn’t help in this case:
GeometryReader { geometry in
ScrollView {
HStack(spacing: .zero) {
Text("This is my greetings to you")
Spacer()
}
if greetings.isEmpty {
ExampleView()
.frame(height: geometry.size.height)
} else {
LazyVStack {
ForEach(greetings, id: .self) {
Text($0)
}
}
}
}
}
Using the code above, PlaceholderView
takes more space than needed. In my case, it should be something like geometry.size.height - hStackHeight
:
Is there a way to make PlaceholderView
take exactly the screen height minus HStack
‘s height? Any guidance is much appreciated.
2
Answers
If you wrap
PlaceholderView
in a secondGeometryReader
then you can use it to get the vertical displacement in the global coordinate space (this being thehStackHeight
you referred to). This can be subtracted from the height:The only thing with this solution is that the height grows when the message at the top is pushed away using a scroll action. This means the message and the placeholder don’t move in sync, which seems a bit odd. So I would probably opt for suppressing the
ScrollView
when there are no greetings to display, as per the answer by superpuccio.EDIT Finally worked it out. An additional
VStack
is necessary inside theScrollView
. Then the adjustment can use the coordinate space of theVStack
. This resolves the issue of the non-synced scroll movement:If you don’t need the placeholder to bounce up and down you can just avoid using a
ScrollView
in case there’s no data to show. I mean:The result is: