I have varying amount of data that needs to be displayed as per image below, notice how when there is odd amount of data, grid adopts to stretch respected items to span across 2 columns
So far, my best stab at this was to have a LazyVGrid
like this
LazyVGrid(
columns: [GridItem(.adaptive(minimum: thirdOfScreen, maximum: .infinity))],
spacing: 8
) {
// ...
}
here thirdOfScreen
is essentially what it says, a third of the screen width. This was my attempt to force only 2 items per row (used third and not half to account for various paddings between and around items).
This worked to an extent, however if there are 1 or 3 items, they don't stretch to full width of the row.
It is possible to do this with a LazyVStack
with HStack
s inside it. You want the items in each HStack
to fill the HStack
equally.
All you need to do is to split the data you want to display into chunks of 2, and use .frame(maxWidth: .infinity)
on each item so they fill the HStack
equally.
Here is an example implementation that uses chunks(ofCount:)
from Swift Algorithms, and Extract
from View Extractor.
import Algorithms
import ViewExtractor
struct MyGrid<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
Extract(content) { views in
let chunksOf2 = views.chunks(ofCount: 2)
LazyVStack {
// use the id of the first view in the chunk of 2 as the id of the ForEach
ForEach(chunksOf2, id: \.first?.id) { rowViews in
HStack {
ForEach(rowViews) { view in
view
.frame(maxWidth: .infinity)
}
}
}
}
}
}
}
You technically don't need to add any dependencies if you don't like dependencies. It's not hard to write a chunks(ofCount:)
yourself, and View Extractor is small enough that you can easily look at its source code and write something similar yourself.
Usage:
struct ContentView: View {
var body: some View {
MyGrid {
ForEach((0..<10).map { String($0) }, id: \.self) { i in
Text(i)
.padding()
.frame(maxWidth: .infinity)
.background(.yellow)
}
}
}
}
The slight downside of this approach is that animations look a bit janky if an item is inserted in/removed from the "grid", except in the last row, where the animation looks fine.