In the first version of SwiftUI, there was no equivalent functionality for UICollectionView. Developers had to wrap it themselves or rely on many third-party libraries. In SwiftUI 2.0, Apple provided Grid widgets through LazyVGrid and LazyHGrid. The implementation of this widget is very much in the style of SwiftUI, and it is significantly different from many third-party libraries.
Basic Usage
struct GridTest1: View {
let columns = [
GridItem(.adaptive(minimum: 50))
//adaptive adjusts itself to fit as many items as possible in a row or column
//fixed has a fixed size e.g., GridItem(.fixed(50)), and the number of items in each row or column must be explicitly set
//flexible is similar to fixed, but the size of each item can be adjusted flexibly; the number of items also needs to be set explicitly
//These types can be mixed
]
var body: some View {
ScrollView{
LazyVGrid(columns: columns, //row and column settings
alignment: .center,
spacing: 20, //spacing between items in a row or column
pinnedViews: [.sectionHeaders]
//if there are sections, pin the header or footer during scrolling
){
Section(header:Text("Header")){
ForEach(0...1000,id:\.self){ id in
Text(String(id))
.foregroundColor(.white)
.padding(.all, 10)
.background(Rectangle().fill(Color.orange))
}
}
}
}
}
}
Mixing LazyVGrid and LazyHGrid
struct CombineGrid: View {
var body: some View {
ScrollView{
LazyVGrid(columns: [GridItem(.adaptive(minimum:40))], alignment: .center, spacing: 10){
ForEach(0...40,id:\.self){ id in
cell(id:id,color:.red)
}
}
//Horizontal scrolling
ScrollView(.horizontal) {
LazyHGrid(rows: [GridItem(.fixed(50)),GridItem(.fixed(50))]){
ForEach(0...100,id:\.self){id in
cell(id:id,color:.green)
}
}
}
.frame(height: 240, alignment: .center)
LazyVGrid(columns: [GridItem(.adaptive(minimum:40))], alignment: .center, spacing: 10){
ForEach(0...100,id:\.self){ id in
cell(id:id,color:.blue)
}
}
}
}
func cell(id:Int,color:Color) -> some View{
RoundedRectangle(cornerRadius: 10)
.fill(color)
.frame(width: 50, height: 50)
.overlay(Text("\(id)").foregroundColor(.white))
}
}
This code displays normally when scrolled up quickly, but the middle LazyHGrid shows anomalies when scrolled up slowly. This is likely a bug. Current environment: Xcode Version 12.0 beta 2 (12 A 6163 b)
Example with Various Parameters Mixed
import SwiftUI
struct GridTest: View {
@State var data = (1...1000).map{i in CellView(item:i, width: CGFloat(Int.random(in: 30...100)), height: CGFloat(Int.random(in: 40...80)))}
let column1 = [
GridItem(.adaptive(minimum: 40, maximum: 80))
]
let column2 = [
GridItem(.flexible()),
]
let column3 = [
GridItem(.fixed(100)),
]
@State var selection = 1
@State var alignment:HorizontalAlignment = .leading
@State var alignmentSelection = 0
@State var spacing:CGFloat = 10
var body: some View {
VStack{
Picker("", selection: $selection){
Text("adaptive").tag(0)
Text("flexible").tag(1)
Text("fixed").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.labelsHidden()
Picker("",selection:$alignmentSelection){
Text("leading").tag(0)
Text("center").tag(1)
Text("trailing").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.labelsHidden()
Slider(value: $spacing, in: -100...100
){Text("spacing")}
Text("\(spacing)")
.onChange(of: alignmentSelection) { value in
switch value{
case 0:
alignment = .leading
case 1:
alignment = .center
case 2:
alignment = .trailing
default:
break
}
}
Button("shuffle"){
withAnimation(Animation.easeInOut){
data.shuffle()
}
}
ScrollView{
let colums = [column1,column2,column3]
LazyVGrid(columns: colums[selection], alignment: alignment, spacing: spacing, pinnedViews: [.sectionHeaders]){
Section(header: Text("header")){
ForEach(data,id:\.id){ view in
view
}
}
}
}
}
}
}
struct CellView:View,Identifiable{
let id = UUID()
let item:Int
let width:CGFloat
let height:CGFloat
let colors:[Color] = [.red,.blue,.yellow,.purple,.pink,.green]
var body: some View{
Rectangle()
.fill(colors.randomElement() ?? Color.gray)
.frame(width: width, height: height, alignment: .center)
.overlay(Text("\(item)").font(.caption2))
}
}
**Since it’s a lazy display, if you shuffle before all cells are scrolled into view, the cells that haven’t been created won’t move in an animated way.
Currently, LazyGrid lacks the ability to automatically avoid collisions and cannot implement the Waterfall Grid effect.