Skip to content

Instantly share code, notes, and snippets.

@weAreJack
Last active September 9, 2024 18:51
Show Gist options
  • Save weAreJack/4c54c9cd73172fc794dc183cb0859388 to your computer and use it in GitHub Desktop.
Save weAreJack/4c54c9cd73172fc794dc183cb0859388 to your computer and use it in GitHub Desktop.
VGrid that allows dynamic height for items.
import SwiftUI
struct DynamicHeightVGrid: Layout {
var numberOfColumns: Int
var horizontalSpacing: CGFloat
var verticalSpacing: CGFloat
init(
numberOfColumns: Int = 2,
horizontalSpacing: CGFloat = 8,
verticalSpacing: CGFloat = 8
) {
self.numberOfColumns = numberOfColumns
self.horizontalSpacing = horizontalSpacing
self.verticalSpacing = verticalSpacing
}
// Calculate the total size needed to accommodate all subviews
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
var totalHeight: CGFloat = 0
let width = proposal.width ?? 0
let columnWidth = (width - (CGFloat(numberOfColumns - 1) * horizontalSpacing)) / CGFloat(numberOfColumns)
var columnHeights = Array(repeating: CGFloat(0), count: numberOfColumns)
// Distribute subviews across columns
for (index, subview) in subviews.enumerated() {
let column = index % numberOfColumns
let subviewSize = subview.sizeThatFits(ProposedViewSize(width: columnWidth, height: nil))
columnHeights[column] += subviewSize.height + verticalSpacing
}
totalHeight = columnHeights.max() ?? 0 // Find the max column height for total height
return CGSize(width: width, height: totalHeight)
}
// Place subviews in their calculated positions
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let width = bounds.width
let columnWidth = (width - (CGFloat(numberOfColumns - 1) * horizontalSpacing)) / CGFloat(numberOfColumns)
var columnHeights = Array(repeating: CGFloat(0), count: numberOfColumns)
for (index, subview) in subviews.enumerated() {
let column = index % numberOfColumns
let xOffset = bounds.minX + CGFloat(column) * (columnWidth + horizontalSpacing)
let yOffset = bounds.minY + columnHeights[column]
let subviewSize = subview.sizeThatFits(ProposedViewSize(width: columnWidth, height: nil))
subview.place(at: CGPoint(x: xOffset, y: yOffset), proposal: ProposedViewSize(width: columnWidth, height: subviewSize.height))
columnHeights[column] += subviewSize.height + verticalSpacing
}
}
}
// Usage
DynamicHeightVGrid {
ForEach(items) { item in
// Your views
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment