I am coding useing swiftUI and I have a vertical scrollView
(see screenshots), and inside that scrollView
I have another horizontal scrollView
, and below that I have a VStack
that I want the height to fill the rest of the screen to the bottom of the vertical scrollView
, but I can't seem to make it work.
The content in the vertical scrollView
can be larger than the actually remaining space in some cases that is why I need a scrollView, but in some other cases the content is smaller than the remaining space
Here is the code I have :
VStack {
HeaderView
ScrollView(.vertical, showsIndicators: false) {
FriendsHorizontalScrollView()
VStack {
// I want this view to take all the remaining height left in the scrollView
FullHeightView()
}
.frame(width: UIScreen.main.bounds.width)
}
}
What I end up having is something like this :
What I want to have :
I have tried several solutions like using geometryReader or putting .frame(maxHeight: .infinity)
on the VStack
but nothing seems to work properly.
Here is a demo of possible approach based on view preferences (ViewHeightKey
is taken from my this solution. Tested with Xcode 12 / iOS 14.
struct DemoLayoutInScrollView: View {
@State private var height1: CGFloat = .zero
@State private var height2: CGFloat = .zero
var body: some View {
VStack(spacing: 0) {
HeaderView()
GeometryReader { gp in
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 0) {
FriendsHorizontalScrollView()
.background(GeometryReader {
Color.clear
.preference(key: ViewHeightKey.self, value: $0.frame(in: .local).size.height)
})
.onPreferenceChange(ViewHeightKey.self) { self.height1 = $0 }
VStack(spacing: 0) {
// I want this view to take all the remaining height left in the scrollView
FullHeightView()
.background(GeometryReader {
Color.clear
.preference(key: ViewHeightKey.self, value: $0.frame(in: .local).size.height)
})
}.frame(height: max(gp.size.height - self.height1, self.height2))
.background(Color.yellow)
}
}
.onPreferenceChange(ViewHeightKey.self) { self.height2 = $0 }
}
}.frame(maxWidth: .infinity)
}
}
replicated helper views (for testing)
struct FriendsHorizontalScrollView: View {
var body: some View {
Text("Horizontal Scroller")
.frame(maxWidth: .infinity)
.frame(height: 100)
.background(Color.green)
}
}
struct FullHeightView: View {
var body: some View {
ZStack {
Color.red
Text("Dynamic Content")
}
.frame(maxWidth: .infinity)
.frame(height: 300)
}
}
struct HeaderView: View {
var body: some View {
Rectangle().foregroundColor(.blue)
.frame(height: 60)
.overlay(Text("Header"))
}
}