2

I'm using a LazyVGrid in a ScrollView to display cells in either a 1 (portrait) or 2 (landscape) column layout. However, the height of shorter cells in a row does not expand to match the taller cell in the same row and looks pretty terrible.

How can I ensure the height is always the same for every cell in a row? Obviously I don't want a fixed height for every cell. (To be clear, I want "Church - Eastbound" to be as tall as "Church & Market" and "West Portal" to be as tall as "Forest Hill".

ScrollView(.vertical) {
    LazyVGrid(
        columns: [GridItem(.adaptive(minimum: 400))],
        alignment: .leading,
        spacing: 16
    ) {
        ForEach(sharedFavorites.favoriteStops.indices, id: \.self) { index in
            let favorite = sharedFavorites.favoriteStops[index]
            
            NavigationLink(
                destination: SingleStationView(
                    station: favorite.station,
                    direction: favorite.direction
                )
            ) {
                BoardRow(favorite: favorite, stop: favorite.observableStop)
                    .padding()
                    .background(Color(.secondarySystemGroupedBackground))
                    .cornerRadius(10)
                    .frame(maxHeight: .infinity)
            }
        }
    }
}

Screenshot:

2-column grid. In each row, the cells are centered vertically, resulting in empty space above and below the shorter cell.

I tried .frame(maxHeight: .infinity) on both the BoardRow view and the inner contents of BoardView (which is just a normal VStack). It didn't work.

aheze
  • 24,434
  • 8
  • 68
  • 125

1 Answers1

0

You were really close — just needed to put the .frame(maxHeight:) before .background.

struct ContentView: View {
    var body: some View {
        ScrollView(.vertical) {
            LazyVGrid(
                columns: [GridItem(.adaptive(minimum: 160))],
                alignment: .leading,
                spacing: 16
            ) {
                ForEach([0, 1, 2, 5, 6, 3], id: \.self) { index in

                    BoardCell(index: index)
                        .padding()
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
                        .background(Color(.secondarySystemGroupedBackground)) /// `background` goes after the frame!
                        .cornerRadius(10)
                }
            }
            .padding(20)
        }
        .background(Color(.secondaryLabel))
    }
}

/// I recreated your view for testing purposes
struct BoardCell: View {
    var index: Int

    var body: some View {
        VStack(alignment: .leading) {
            Text("Powell (Westbound)")

            ForEach(0 ..< index) { _ in
                HStack {
                    Circle()
                        .fill(.green)
                        .frame(width: 30, height: 30)

                    Text("4")

                    Text("19")

                    Text("17")
                }
            }
        }
    }
}

Result:

2-column grid. In each row, cells share the height of the tallest cell. Inner content is aligned to the top-left edge.
aheze
  • 24,434
  • 8
  • 68
  • 125
  • Thanks for going above and beyond here with this example! Unfortunately this didn't work for me, I copy-pasted your code into Xcode and the result is this: ![screenshot](https://i.imgur.com/gWSpoba.png) . I'm wondering if this behavior is different on iOS 15 vs 16? I'm currently using Xcode 13 still – Naren Hazareesingh Dec 09 '22 at 21:06
  • Hmm, possibly. I'm on iOS 16 – aheze Dec 09 '22 at 22:59
  • I'm experimenting kind of the same problem. While in iOS 16 works as expected, in 15 the cells are shrinking to its content in the same way as your example. – juanjovn May 01 '23 at 19:00