2

I have a set of child views (GridView1 and GridView2) within a scrollview. The child views are within a VStack since I need them one below the other. I have a GeometryReader wrapping the child views and each of the child views have a GeometryReader inside them. I need the GeometryReader inside the child view to determine the width of the column spacing I need in a LazyVGrid.

The problem is that, using a GeometryReader inside the Child views causes the two child views stack on top of each other. I have tried to set the frame size of the child view but that limits the vertical scrolling and is not giving me the right result.

I would appreciate any help in resolving this problem.

ContentView:

struct ContentView: View {
    var body: some View {
        GeometryReader { geo in
            ScrollView {
                VStack(spacing: 20) {
                    GridView1()
                    GridView2()
                }//.frame(minHeight: 0, maxHeight: .infinity)
            }
        }
        .padding()
    }
}

GridView1:

struct GridView1: View {
    var body: some View {
        GeometryReader { g in
            let maxwidth = g.size.width/6 > 100 ? g.size.width/6 : 100
            let columns = Array(repeating: GridItem(.flexible(minimum: 100, maximum: maxwidth), spacing: 0), count: 6)
            
            ScrollView(.horizontal) {
                LazyVGrid(columns: columns, alignment: .leading, spacing: 10, pinnedViews: [.sectionHeaders]) {
                    Section(header: Text("Grid 1").font(.title)) {
                        ForEach(0...200, id:\.self) { index in
                            Text("\(index)").frame(maxWidth: .infinity)
                        }
                    }
                }
            }
            .background(Color.blue)
        }
    }
}

GridView2 (GridView1 and GridView2 are essentially the same thing)

struct GridView2: View {
    var body: some View {
        GeometryReader { g in
            let maxwidth = g.size.width/10 > 100 ? g.size.width/10 : 100
            let columns = Array(repeating: GridItem(.flexible(minimum: 100, maximum: maxwidth), spacing: 0), count: 10)
            ScrollView(.horizontal) {
                LazyVGrid(columns: columns, alignment: .leading, spacing: 20, pinnedViews: [.sectionHeaders]) {
                    Section(header: Text("Grid 2").font(.title)) {
                        ForEach(1000...1200, id:\.self) { index in
                            ZStack {
                                Text("\(index)")
                            }
                            .frame(maxWidth: .infinity)
                            .background(Color.green)
                        }
                    }//.frame(minHeight: 0, maxHeight: .infinity)
                }
            }//.frame(minHeight: 1000, maxHeight: .infinity)
            //.frame(maxWidth: .infinity, maxHeight: .infinity)
            //.background(Color.red)
        }
    }
}

here is what I am expecting:

enter image description here

enter image description here

Here is what I am currently getting. As you can see below, the child views are bunching up at the top.

enter image description here

1 Answer 1

1

Instead of use internal GeometryReader that confuses external ScrollView, pass width from top GeometryReader into sub-views grids.

Here is worked solution. Tested with Xcode 12.1 / iOS 14.1

demo

struct ContentView: View {
    var body: some View {
        GeometryReader { geo in
            ScrollView {
                VStack(spacing: 20) {
                    GridView1(width: geo.size.width)
                    GridView2(width: geo.size.width)
                }
            }
        }
        .padding()
    }
}

struct GridView1: View {
    let width: CGFloat
    var body: some View {
        let maxwidth = width/6 > 100 ? width/6 : 100
        let columns = Array(repeating: GridItem(.flexible(minimum: 100, maximum: maxwidth), spacing: 0), count: 6)
        
        ScrollView(.horizontal) {
            LazyVGrid(columns: columns, alignment: .leading, spacing: 10, pinnedViews: [.sectionHeaders]) {
                Section(header: Text("Grid 1").font(.title)) {
                    ForEach(0...200, id:\.self) { index in
                        Text("\(index)").frame(maxWidth: .infinity)
                    }
                }
            }
        }
        .background(Color.blue)
    }
}

struct GridView2: View {
    let width: CGFloat
    var body: some View {
        let maxwidth = width/10 > 100 ? width/10 : 100
        let columns = Array(repeating: GridItem(.flexible(minimum: 100, maximum: maxwidth), spacing: 0), count: 10)
        ScrollView(.horizontal) {
            LazyVGrid(columns: columns, alignment: .leading, spacing: 20, pinnedViews: [.sectionHeaders]) {
                Section(header: Text("Grid 2").font(.title)) {
                    ForEach(1000...1200, id:\.self) { index in
                        ZStack {
                            Text("\(index)")
                        }
                        .frame(maxWidth: .infinity)
                        .background(Color.green)
                    }
                }
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

this works! Thank you. However, I am wondering what is the right way to use the GeometryReader because this limits the use of GeometryReader in downstream views. Any pointers or examples you can point me to. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.