Reputation: 13585
I'm trying to make a sub view which contains a drawing which I want the size to be proportional to a fraction of the parent container.
This works fine except when put inside a scroll view somewhere up the hierarchy.
As seen from the screenshots when inside of the stack the loudest as expected. But when you put inside a scroll view the size of the geometry reader collapses to near zero and its children overflow its boundaries. As though it's rendering its children on a different Z index. In fact if you remove the wrapping VStack from the geometry render contents it doesn't fact layout all its children as though it were wrapped in a ZStack.
EDIT: To be clear: the ScrollView is not owned by the component. The component should not be aware if it's in a ScrollView or not - it's just a poor helpless component, being thrown around. That's why I put the ScrollView into the preview code, not the component.
I've tried all sorts of combinations of fixed sizes and men and mags and ideal. The only work around I could find was this hacky solution - the edited part of the question near the bottom where the width reported by the geometry reader is captured through a workaround into a state variable and then re-used to set the frame size of a sibling view.
Note, I'm a complete beginner. There seems to be some interaction between the scroll view and the geometry reader that is beyond my current understanding.
Seems to be a confusing topic.
import SwiftUI
struct ScrollViewGeoReader: View {
var body: some View {
GeometryReader{ g in
VStack{
let width = g.size.width
Circle().frame(width: width/3, height: width/3, alignment: .center)
Text("inside geo")
Text("inside geo")
Text("inside geo \(width)")
Text("inside geo")
Text("inside geo")
}
.border(Color.green, width: 2)
}
.border(Color.red, width: 3)
}
}
struct ScrollViewGeoReader_Previews: PreviewProvider {
static var previews: some View {
VStack {
// VStack {
ScrollView {
ScrollViewGeoReader()
Text("Next scrollview item")
}
.border(Color.blue, width: 2)
}
}
}
ZStack (expected layout):
ScrollView (see how the red frame of the geometry read it has collapsed to size 10):
Also note that the same problem occurs with or without the circle, which is also a problem I have. So it's not chicken / egg as far as the width capturing is concerned, at least in terms of Circles. I would have though the Text components know their own size, and would tell the GR.
vs
Upvotes: 11
Views: 3167
Reputation: 258345
Here is scratchy (w/o subviews separation) possible solution for layout. If/when internal subviews separated the geometry width can be injected by constructor arguments.
Tested with Xcode 12.
struct TestScrollViewWithGeometry: View {
var body: some View {
GeometryReader{ g in
ScrollView {
VStack{
let width = g.size.width
Circle().frame(width: width/3, height: width/3, alignment: .center)
Text("inside geo")
Text("inside geo")
Text("inside geo \(width)")
Text("inside geo")
Text("inside geo")
}
.border(Color.green, width: 2)
Text("Next scrollview item")
}
.border(Color.blue, width: 2)
}
.border(Color.red, width: 3)
}
}
Upvotes: 0