Apple says: "Container views that arrange its child views in a grid that grows vertically or horizontally respectively, creating items only as needed."
Creating views as needed means that only views that are a visible or are about to be visible will be created, so if you are scrolling through a long list of items, views will not be created at the same, only the ones that need to be display at that particular time.
LazyVGrid
and LazyHGrid
will eventually replace UIKit's UICollectionView
, but for now they are still not as powerful.
Apple says: "A description of a single grid item, such as a row or a column."
GridItems describe how items of a LazyVGrid
or LazyHGrid
will be laid out and which size each of them will have.
// $$liquidcoderID-LazyVHGrid1
init(GridItem.Size, spacing: CGFloat?, alignment: Alignment?)
Fixed gridItems (columns) will keep the same size no matter how many of them you add in a grid which will make them overflow. Use fixed items if you know that the size of the content inside them will stay constant.
LazyVGrid
uses HorizontalAlignment
meaning they can only be aligned along the x-axis as you can see in the preview.
Note: Using a
LazyVGrid
makes the 100 value in the.fixed
size be the width, hence the need to set the height on theRectangle
inside theForEach
.
// $$liquidcoderFilename-ContentView
import SwiftUI
extension HorizontalAlignment {
...
}
struct ContentView: View {
// highlight-start
@State var columns: [GridItem] = [GridItem(.fixed(100))]
@State var alignment: HorizontalAlignment = .center
// highlight-end
var body: some View {
VStack {
HStack { ... }
// highlight-start
ScrollView {
LazyVGrid(columns: columns, alignment: alignment) {
ForEach((0..<79), id: \.self) { i in
Rectangle()
.frame(height: 100)
}
}.font(.largeTitle)
}
// highlight-end
HStack { ... }
}
}
}
LazyHGrid
uses VerticalAlignment
meaning they can only be aligned along the y-axis as you can see in the preview.
Note: Using a
LazyHGrid
makes the 100 value in the.fixed
size be the height, hence the need to set the width on theRectangle
inside theForEach
.
This is the opposite of what we have done with the LazyVGrid
// $$liquidcoderFilename-ContentView
import SwiftUI
extension VerticalAlignment {
...
}
struct ContentView: View {
// highlight-start
@State var rows: [GridItem] = [GridItem(.fixed(100)) ]
@State var alignment: VerticalAlignment = .center
// highlight-end
var body: some View {
VStack {
HStack { ... }
// highlight-start
ScrollView(.horizontal) {
LazyHGrid(rows: rows, alignment: alignment) {
ForEach((0..<79), id: \.self) { i in
Rectangle()
.frame(width: 100)
}
}.font(.largeTitle)
}
// highlight-end
HStack { ... }
}
}
}
Flexible size is the same as fixed in such a way that the number of rows or columns is equal to the count of GridItem
array. However, the width of each column or height of each row will fill the available space, unless you specify a minimum
and maximum
thresholds.
// $$liquidcoderID-LazyVHGrid5
case flexible(minimum: CGFloat = 10, maximum: CGFloat = .infinity)
As you can see when we only have 1 column, each item fill the entire width, but as soon as we start adding grid items to the array, the entire width is divided equally to accommodate each item.
Use this size if you know exactly how many rows or columns you will have.
// $$liquidcoderID-LazyVHGrid6
// $$liquidcoderFilename-ContentView
struct ContentView: View {
// highlight-start
@State var columns: [GridItem] = [GridItem(.flexible())]
// highlight-end
var body: some View {
VStack {
HStack {
Text("# of gridItems: ")
+ Text("\(columns.count)")
.bold()
.foregroundColor(.blue)
}
// highlight-start
ScrollView {
LazyVGrid(columns: columns) {
ForEach((0..<100), id: \.self) { i in
Rectangle()
.foregroundColor( i.isMultiple(of: 2) ? .blue : .yellow)
}
}.font(.largeTitle)
}
// highlight-end
HStack {
Button(action: {
columns.append(GridItem(.flexible()))
}, label: {
Text("Add Fixed GridItem")
.padding()
.background(Color.blue)
.foregroundColor(.white)
})
}
}
}
}
With adaptive
size, you don't need mulitple gridItems to have multiple columns or rows, you just need an array with a single item, and play with the minimum and maximum values.
The grid will create as many columns or rows depending if it's a LazyVGrid
or a LazyHGrid
respectively as possible, and the width of each column or height of each row will depend on the content that each column and row contains.
// $$liquidcoderID-LazyVHGrid8
// $$liquidcoderFilename-ContentView
import SwiftUI
struct ContentView: View {
// highlight-start
@State var columns: [GridItem] = [GridItem(.adaptive(minimum: 10))]
// highlight-end
// highlight-start
@State private var min = 10
// highlight-end
var body: some View {
VStack {
HStack {
Text("Minimum ")
+ Text("\(min)")
.bold()
.foregroundColor(.blue)
}
// highlight-start
ScrollView {
LazyVGrid(columns: columns) {
ForEach((0..<100), id: \.self) { i in
Rectangle()
.foregroundColor( i.isMultiple(of: 2) ? .blue : .yellow)
}
}.font(.largeTitle)
}
// highlight-end
HStack {
Button(action: {
min += 10
columns = [GridItem(.adaptive(minimum: CGFloat(min)))]
}, label: {
Text("Add Fixed GridItem")
.padding()
.background(Color.blue)
.foregroundColor(.white)
})
}
}
}
}
You can also mix multiple different sizes to fit your needs.
// $$liquidcoderID-LazyVHGrid9
// $$liquidcoderFilename-ContentView
import SwiftUI
struct ContentView: View {
// highlight-start
var columns: [GridItem] = [GridItem(.adaptive(minimum: 30)), GridItem(.fixed(70)), GridItem(.flexible())]
// highlight-end
var body: some View {
VStack {
// highlight-start
ScrollView {
LazyVGrid(columns: columns) {
ForEach((0..<100), id: \.self) { i in
Rectangle()
.foregroundColor( i.isMultiple(of: 2) ? .blue : .yellow)
}
}.font(.largeTitle)
}
// highlight-end
}
}
}
Grids in swiftUI are very powerful seeing that it's still only their first iteration which makes me wonder what type of magic will we get from them in future versions of swiftUI? The only thing I can say is that the future brighter guys. Happy coding!!!