4

I'm building a grid with cards which have an image view at the top and some text at the bottom. Here is the swift UI code for the component:

struct Main: View {
    var body: some View {
        ScrollView {
            LazyVGrid(columns: .init(repeating: .init(.flexible()), count: 2)) {
                ForEach(0..<6) { _ in
                    ZStack {
                        Rectangle()
                            .foregroundColor(Color(UIColor.random))
                        VStack {
                            Rectangle()
                                .frame(minHeight: 72)
                            Text(ipsum)
                                .fixedSize(horizontal: false, vertical: true)
                                .padding()
                        }
                    }.clipShape(RoundedRectangle(cornerRadius: 10))
                }
            }.padding()
        }.frame(width: 400, height: 600)
    }
}

This component outputs the following layout:

enter image description here

This Looks great, but I want to add a Geometry reader into the Card component in order to scale the top image view according to the width of the enclosing grid column. As far as I know, that code should look like the following:

struct Main: View {
    var body: some View {
        ScrollView {
            LazyVGrid(columns: .init(repeating: .init(.flexible()), count: 2)) {
                ForEach(0..<6) { _ in
                    ZStack {
                        Rectangle()
                            .foregroundColor(Color(UIColor.random))
                        VStack {
                            GeometryReader { geometry in
                                Rectangle()
                                    .frame(minHeight: 72)
                                Text(ipsum)
                                    .fixedSize(horizontal: false, vertical: true)
                                    .padding()
                            }
                        }
                    }.clipShape(RoundedRectangle(cornerRadius: 10))
                }
            }.padding()
        }.frame(width: 400, height: 600)
    }
}

The trouble is that this renders as the following:

enter image description here

As you can see, I'm not even trying to use the GeometryReader, I've just added it. If I add the geometry reader at the top level, It will render the grid correctly, however this is not of great use to me because I plan to abstract the components into other View conforming structs. Additionally, GeometryReader seems to be contextually useful, and it wouldn't make sense to do a bunch of math to cut the width value in half and then make my calculations from there considering the geometry would be from the top level (full width).

Am I using geometry reader incorrectly? My understanding is that it can be used anywhere in the component tree, not just at the top level.

Thanks for taking a look!

thexande
  • 1,390
  • 12
  • 20

1 Answers1

0

I had the same problem as you, but I've worked it out. Here's some key point.

If you set GeometryReader inside LazyVGrid and Foreach, according to SwiftUI layout rule, GeometryReader will get the suggested size (may be just 10 point). More importantly, No matter what subview inside GeometryReader, it wouldn't affect the size of GeometryReader and GeometryReader's parent view.

For this reason, your view appears as a long strip of black. You can control height by setting GeometryReader { subView }.frame(some size),

Generally, we need two GeometryReader to implement this. The first one can get size and do some Computing operations, then pass to second one.

(Since my original code contains Chinese, it may be hard for you to read, so I can only give a simple structure for you.)

GeometryReader { firstGeo in
    LazyVGrid(columns: rows) {
        ForEach(dataList) { data in
            GeometryReader { secondGeo in
              // subview
            }
            .frame(width: widthYouWantSubViewGet)
        }
    }
}

I just started to learn swift for a week. There may be some mistakes in my understanding. You are welcome to help correct it.

Eriice
  • 127
  • 1
  • 6