1

I'm trying to replicate this UI in SwiftUI using a Grid.

enter image description here

I created the cell like this.

struct MenuButton: View {
    let title: String
    let icon: Image
    
    var body: some View {
        Button(action: {
            print(#function)
        }) {
            VStack {
                icon
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 60, height: 60)
                Text(title)
                    .foregroundColor(.black)
                    .font(.system(size: 20, weight: .bold))
                    .multilineTextAlignment(.center)
                    .padding(.top, 10)
            }
        }
        .frame(width: 160, height: 160)
        .overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.fr_primary, lineWidth: 0.6))
    }
}

And the Grid like so.

struct LoginUserTypeView: View {
    private let columns = [
        GridItem(.flexible(), spacing: 20),
        GridItem(.flexible(), spacing: 20)
    ]
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 30) {
                ForEach(Menu.UserType.allCases, id: \.self) { item in
                    MenuButton(title: item.description, icon: Image(item.icon))
                }
            }
            
            .padding(.horizontal)
            .padding()
        }
    }
}

But on smaller screens like the iPod, the cells are overlapped.

enter image description here

On bigger iPhone screens, still the spacing is not correct.

enter image description here

What adjustments do I have to make so that in every screen size, the cells would show in a proper square shape and equal spacing on all sides?

Isuru
  • 27,485
  • 56
  • 174
  • 278

1 Answers1

1

MenuButton has fixed width and height, thats why it behaves incorrectly.


You could utilise .aspectRatio and .frame(maxWidth: .infinity, maxHeight: .infinity) for this:

struct MenuButton: View {
    let title: String
    let icon: Image

    var body: some View {
        Button(action: {
            print(#function)
        }) {
            VStack(spacing: 10) {
                icon
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(maxWidth: 60, maxHeight: 60)
                Text(title)
                    .foregroundColor(.black)
                    .font(.system(size: 20, weight: .bold))
                    .multilineTextAlignment(.center)
            }
            .padding()
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .aspectRatio(1, contentMode: .fill)
        .overlay(RoundedRectangle(cornerRadius: 10).stroke(Color. fr_primary, lineWidth: 0.6))
    }
}
Tomas Jablonskis
  • 3,582
  • 4
  • 20
  • 32
  • Thanks for the response. That indeed fixed my cell sizing issue. However there's a small problem. Even though the cell resizes, the content inside (image and the text) are still the same size. So in smaller screens, it looks like [this](https://i.imgur.com/8OpxPYI.png). Is there a way to resize those elements to fit inside the cell as well? – Isuru Feb 16 '21 at 13:37
  • I tried setting the aspect ratio to the `Text` object. [It's pushing out the image.](https://i.imgur.com/4IKQjXO.png) – Isuru Feb 16 '21 at 13:37
  • @Isuru Update my code. – Tomas Jablonskis Feb 16 '21 at 13:52
  • @Isuru I assume you want to keep your buttons square. – Tomas Jablonskis Feb 16 '21 at 13:55