SwiftUIMidOpen-ended
How do you implement a wrapping flow layout using the SwiftUI `Layout` protocol?
Explanation & Code
struct FlowLayout: Layout {
var horizontalSpacing: CGFloat = 12
var verticalSpacing: CGFloat = 12
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
var width: CGFloat = 0
var height: CGFloat = 0
var rowHeight: CGFloat = 0
let maxWidth = proposal.width ?? .infinity
for subview in subviews {
let size = subview.sizeThatFits(.unspecified)
if width + size.width > maxWidth {
width = 0
height += rowHeight + verticalSpacing
rowHeight = 0
}
width += size.width + horizontalSpacing
rowHeight = max(rowHeight, size.height)
}
height += rowHeight
return CGSize(width: maxWidth, height: height)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
var x: CGFloat = bounds.minX
var y: CGFloat = bounds.minY
var rowHeight: CGFloat = 0
let maxWidth = bounds.width
for subview in subviews {
let size = subview.sizeThatFits(.unspecified)
if x + size.width > maxWidth {
x = bounds.minX
y += rowHeight + verticalSpacing
rowHeight = 0
}
subview.place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size))
x += size.width + horizontalSpacing
rowHeight = max(rowHeight, size.height)
}
}
}
Rate your understanding: