Last active
June 7, 2023 08:10
-
-
Save vahotm/69b750bf1572dc499122095c30f042f7 to your computer and use it in GitHub Desktop.
A non-lazy alternative to LazyVGrid. The difference from LazyVGrid is that VGrid gives equal height to its cells based on the highest cell, hence its non-laziness.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftUI | |
struct VGrid<Cell: View>: View { | |
struct CollectionRow<Cell: View>: View { | |
let indices: Range<Int> | |
let numberOfColumns: Int | |
let spacing: CGFloat | |
let minHeight: CGFloat | |
@ViewBuilder var cellBuilder: (Int) -> Cell | |
@ViewBuilder | |
var body: some View { | |
HStack(spacing: spacing) { | |
ForEach(indices, id: \.self) { index in | |
cellBuilder(index) | |
.frame(minHeight: minHeight) | |
} | |
ForEach(0..<(numberOfColumns - indices.count), id: \.self) { _ in | |
Spacer() | |
.frame(maxWidth: .infinity) | |
} | |
} | |
} | |
} | |
let configuration: VGridConfiguration | |
@ViewBuilder var cellBuilder: (Int) -> Cell | |
@State private var maxRowHeight: CGFloat = 0.0 | |
@ViewBuilder | |
var body: some View { | |
VStack(alignment: configuration.alignment, spacing: configuration.vSpacing) { | |
ForEach(ranges, id: \.self) { rowRange in | |
CollectionRow( | |
indices: rowRange, | |
numberOfColumns: configuration.numberOfColumns, | |
spacing: configuration.hSpacing, | |
minHeight: maxRowHeight, | |
cellBuilder: cellBuilder) | |
.fixedSize(horizontal: false, vertical: true) | |
.readSize { size in | |
maxRowHeight = max(size.height, maxRowHeight) | |
} | |
.frame(minHeight: maxRowHeight) | |
} | |
} | |
} | |
private var ranges: [Range<Int>] { | |
stride(from: 0, to: configuration.itemsCount, by: configuration.numberOfColumns).map { i in | |
let upperBound = min(i + configuration.numberOfColumns, configuration.itemsCount) | |
return i..<upperBound | |
} | |
} | |
init(_ configuration: VGridConfiguration, cellBuilder: @escaping (Int) -> Cell) { | |
self.configuration = configuration | |
self.cellBuilder = cellBuilder | |
} | |
} | |
struct VGridConfiguration { | |
let numberOfColumns: Int | |
let itemsCount: Int | |
let alignment: HorizontalAlignment | |
let hSpacing: CGFloat | |
let vSpacing: CGFloat | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment