Gurmukh Singh
Gurmukh Singh

Reputation: 2017

SwiftUI - LazyVGrid spacing

I have a LazyVGrid like so in SearchView.swift file

let layout = [
    GridItem(.flexible()),
    GridItem(.flexible())
]

NavigationView {
     ZStack {
        VStack {
           ....Some other stuff here
           ScrollView (showsIndicators: false) {
                    LazyVGrid(columns: layout) {
                        ForEach(searchViewModel.allUsers, id: \.uid) { user in
                            NavigationLink(destination: ProfileDetailedView(userData: user)) {
                                profileCard(profileURL: user.profileURL, username: user.username, age: user.age, country: user.city)
                            }
                        }
                    }
                }
           }
      }
}

My profileCard.swift looks like:

var body: some View {
    ZStack {
        Image.image(urlString: profileURL,
                 content:  {
                    $0.image
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        
                 }
        )
        .frame(width: 185, height: 250)
        .overlay(
            LinearGradient(gradient: Gradient(colors: [.clear, .black]), startPoint: .center, endPoint: .bottom)
        )
        .overlay(
            VStack (alignment: .leading) {
                Text("\(username.trimmingCharacters(in: .whitespacesAndNewlines)), ")
                    .font(.custom("Roboto-Bold", size:14))
                    .foregroundColor(Color.white)
                + Text("\(age)")
                    .font(.custom("Roboto-Light", size:14))
                    .foregroundColor(Color.white)
                HStack {
                    Text("\(country)")
                        .font(.custom("Roboto-Light", size:14))
                        .foregroundColor(.white)
                }
            }
            .padding(.leading, 15)
            .padding(.bottom, 15)
            ,alignment: .bottomLeading
        )
        .cornerRadius(12)
    }
}

This is producing 2 different spaces on different screen sizes:

iPhone 12:

enter image description here

iPhone 12 Pro Max

enter image description here

Im trying to get the same amount of spacing between the cards (horizontal and verticle) and the around the cards on all devices, any help on achieving this?

UPDATE

Following the example by @Adrien has gotten me closer to the problem, but when I use an image, the results change completely

let columns = Array(repeating: GridItem(.flexible(), spacing: 20, alignment: .center), count: 2)

ScrollView (showsIndicators: false) {
                LazyVGrid(columns: columns, spacing: 20) {
                    ForEach(searchViewModel.allUsers, id: \.uid) { user in
                        NavigationLink(destination: ProfileDetailedView(userData: user)) {
                                    
                                HStack {
                                    Image("placeholder-avatar")
                                         .resizable()
                                              .aspectRatio(contentMode: .fill)
                                                
                                        }
                                        .frame(maxWidth: .infinity, minHeight: 240) // HERE 1
                                        .background(Color.black)
                                        .cornerRadius(25)
                                }
                            }
                        }.padding(20)
                    }

enter image description here

Upvotes: 3

Views: 6576

Answers (2)

Adrien
Adrien

Reputation: 1927

The array of GridItem only fixes the behavior of the container of each cell. Here it is flexible, but that does not mean that it will modify its content.

The View it contains can have three different behaviors :

  1. it adapts to its container: like Rectangle, Image().resizable(), or any View with a .frame(maxWidth: .infinity, maxHeight: .infinity)) modifier.
  2. it adapts to its content (like Text, or HStack).
  3. it has a fixed size (as is your case with .frame(width: 185, height: 250))

If you want the same spacing (vertical and horizontal) between cells, whatever the device, the content of your ProfileDetailedView must adapt to its container :

  1. you have to modify your cell so that it adopts behavior 1.

  2. you can use the spacing parameters of yours GridItem (horizontal spacing) and LazyVGrid (vertical).

Example:

struct SwiftUIView5: View {
    let columns = Array(repeating: GridItem(.flexible(), spacing: 20, alignment: .center), count: 2)  // HERE 2
    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 20) {  // HERE 2
                ForEach((1...10), id: \.self) { number in
                    HStack {
                        Text(number.description)
                            .foregroundColor(.white)
                            .font(.largeTitle)
                    }
                    .frame(maxWidth: .infinity, minHeight: 200) // HERE 1
                    .background(Color.black)
                    .cornerRadius(25)
                }
            }
            .padding(20)  // HERE 2
        }
    }
}

Example

Upvotes: 6

Mundi
Mundi

Reputation: 80271

Actually, the spacing is a function of the screen size, in your case. You have hard-coded the size of the card (185x250), so the spacing is as expected, a bit tighter on smaller screens, bit more airy on larger screens.

Note that the vertical spacing is consistent and as expected. This seems logical because there is no vertical size constraint.

BTW, the two screenshots are not the same size, otherwise this aspect would be more obvious.

If you want to keep the size of the card fixed, you can perhaps at least keep the horizontal space between them constant, but then you will have larger margins on the sides.

Or you can adjust the size of the card dynamically. Check out GeometryReader, which will help you access runtime screen sizes.

Upvotes: 0

Related Questions