8

I am implementing a LazyVGrid but would like all the cells to optimally have both the same vertical and horizontal dimensions. Currently my view looks like this:

enter image description here

With the addition of shadows, it is very important that the cell backgrounds are resized to all match. So far, my code is:

struct IconButton: View {
    
    let icon: Icon
    
    var body: some View{
        Button {
            
        } label:{
            VStack{
                Image(icon.imageName)
                    .resizable()
                    .scaledToFit()
                Text(icon.title)
                    .font(.title3)
                    .bold()
                    .foregroundColor(.black)
                    .multilineTextAlignment(.center)
            }
        }
    }
}    

ScrollView{
            LazyVGrid(columns: Array(repeating: .init(), count: 3)){
                ForEach(icons, id: \.self){icon in
                    IconButton(icon: icon)
                }
                .padding(12)
                .background(Color.white)
                .cornerRadius(8)
                .shadow(radius: 4)
            }
            .padding()
        }

So far I've attempted to change the GridColumns parameters, as well as setting the frame from within the IconButton either directly with .frame() or with something like .aspectRatio(). However these are all related to the button itself, rather than the size of all the other buttons. This SO answer has an approach to keep track of the largest dimensions for any view, and then subsequently sets all other views with the same frame. However though it seems to work from the answer, this approach seems overly complex, given that it is dealing with subviews on a list view, rather than the direct child items of a grid view. Is there a more intuitive approach for GridView?

The primary issue I can imaging coming up with trying to implement something like this is that since it is a lazy grid, the cells at the bottom are not laid out until necessary, and thus as they are generated, this might require the sizes of other cells to change, if a cell with larger dimensions is found. I don't foresee this to be particularly problematic with my implementation, as I only have about 15 cells. Does this indicate that I should be bothering with a LazyGrid?

Acoop
  • 2,586
  • 2
  • 23
  • 39

1 Answers1

5

The cells themselves are actually the same size. You'll notice that no item spills over into the area of another row. What you have here, however, is that the content inside the cells is hugging to it's intrinsic size, rather than occupying as much of the space as it can.

I have not tested this, but one thing you can try is to wrap it all in a GeometryReader and then use the proxy size to explicitly set your own size:

GeometryReader { proxy in
  Button(...)
    .frame(width: proxy.size.width, height: proxy.size.height)
}

I'm not personally a fan of this one, so you can also try using the "flexible" frame:

Button(...)
  .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
Procrastin8
  • 4,193
  • 12
  • 25