New iOS Dev
New iOS Dev

Reputation: 2057

How to make number of items for iPhone and iPad in LazyVGrid?

I have LazyVGrid in which i want to make 2 item per row for iPhone and 4 per row in iPad, I am not sure how should i give condition in SwiftUI and how to restrict number of rows

//
//  ContentView.swift
//  DemoProject


import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>
    private var gridItemLayout = [GridItem(.adaptive(minimum: 100))]

    @StateObject private var viewModel = HomeViewModel()

    var body: some View {
        GeometryReader { geometry in
            NavigationView {
                ScrollView {
                    LazyVGrid(columns: gridItemLayout, spacing: 20) {
                        ForEach(viewModel.results, id: \.self) {
                            let viewModel = ResultVM(model: $0)

                            NavigationLink(destination: {
                                DetailView()
                            }, label: {
                                SearchResultRow(resultVM: viewModel)

                            })
                        }
                    }
                }
            }
            .onAppear(perform: {
                viewModel.performSearch()
            })
        }
    }
}

struct SearchResultRow: View {

    let resultVM: ResultVM

    var body: some View {
        HStack {
            RoundedRectangle(cornerRadius: 16).fill(.yellow)
                .frame(maxWidth: .infinity).aspectRatio(1, contentMode: .fit)
                .overlay(Text(resultVM.trackName))
                .onTapGesture {
                }

        }.padding()
            .background(Color.red)
    }
}

enter image description here

Upvotes: 4

Views: 831

Answers (3)

ramzesenok
ramzesenok

Reputation: 6941

While the provided answers will work per se they can get tricky when using your app in a multitasking mode on the iPad: Split View or Slide Over. In case of Slide Over the width of your app on the iPad will be the same as it would be on the iPhone but if you'll check for the interface idiom, you'll still get .pad (well, cause you are using iPad). And the interface therefore might get broken – you'll get an iPad interface on an iPhone-sized app.

But there's a way to do it right – UserInterfaceSizeClass. Specifically you'll need a horizontal size class. This enum has 2 cases (state of February 2023): .compact and .regular. In simple words the UserInterfaceSizeClass is .compact when the width of an app is similar to the iPhone's width (Slide Over or Slit View in Portrait Mode or just an actual iPhone) and .regular when the width is similar to the iPad's width (normal iPad Portrait or Landscape mode, Split View in Landscape Mode). Based on this parameter you can decide how to render your interface

So, enough theory, here's the code to copy-paste :)

struct YourView: View {
    @Environment(\.horizontalSizeClass)
    var horizontalSizeClass

    var columns: [GridItem] {
        switch horizontalSizeClass {
        case .compact:
            return [GridItem(), GridItem()] // Using 2 columns if it's narrow
        case .regular:
            return [GridItem(), GridItem(), GridItem(), GridItem()] // Using 4 columns if it's wide
        // Cover `nil` and `@unknown default` here
        }
    }

    var body: some View {
        LazyVGrid(columns: columns) {
            ...
        }
    }
}

Upvotes: 0

cora
cora

Reputation: 2102

Something like this:

LazyVGrid(columns: Array(repeating: .init(.flexible()),
                        count: UIDevice.current.userInterfaceIdiom == .pad ? 4 : 2)) {
        ForEach(categories, id: \.name) { category in
                    
        }
}

Upvotes: 3

RelativeJoe
RelativeJoe

Reputation: 5104

Well you can make your gridItemLayout to the following:

private var gridItemLayout = [
    GridItem(spacing: 2),//your spacing
    GridItem(spacing: 2),//your spacing
]

And add in an init (recommended) or in .onAppear:

if UI_USER_INTERFACE_IDIOM() == .pad {
    gridItemLayout.append(contentsOf: [GridItem(spacing: 2), GridItem(spacing: 2)]) //your spacing
}

Upvotes: 0

Related Questions