Skip to content

Instantly share code, notes, and snippets.

@aheze
Created July 9, 2023 21:37
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save aheze/1cbd2d36764c978b28aa20a00cb4b5b6 to your computer and use it in GitHub Desktop.
Save aheze/1cbd2d36764c978b28aa20a00cb4b5b6 to your computer and use it in GitHub Desktop.
struct OverflowLayout: Layout {
var spacing = CGFloat(10)
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let containerWidth = proposal.replacingUnspecifiedDimensions().width
let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
return layout(sizes: sizes, containerWidth: containerWidth).size
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
let offsets = layout(sizes: sizes, containerWidth: bounds.width).offsets
for (offset, subview) in zip(offsets, subviews) {
subview.place(at: CGPoint(x: offset.x + bounds.minX, y: offset.y + bounds.minY), proposal: .unspecified)
}
}
func layout(sizes: [CGSize], containerWidth: CGFloat) -> (offsets: [CGPoint], size: CGSize) {
var result: [CGPoint] = []
var currentPosition: CGPoint = .zero
var lineHeight: CGFloat = 0
var maxX: CGFloat = 0
for size in sizes {
if currentPosition.x + size.width > containerWidth {
currentPosition.x = 0
currentPosition.y += lineHeight + spacing
lineHeight = 0
}
result.append(currentPosition)
currentPosition.x += size.width
maxX = max(maxX, currentPosition.x)
currentPosition.x += spacing
lineHeight = max(lineHeight, size.height)
}
return (result, CGSize(width: maxX, height: currentPosition.y + lineHeight))
}
}
/// Usage
OverflowLayout(spacing: 10) {
ForEach(badges) { badge in
Text("Hello!")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment