Reputation: 2057
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)
}
}
Upvotes: 4
Views: 831
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
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
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