Last active
September 9, 2024 18:51
-
-
Save weAreJack/4c54c9cd73172fc794dc183cb0859388 to your computer and use it in GitHub Desktop.
VGrid that allows dynamic height for items.
This file contains 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 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