Skip to content

Instantly share code, notes, and snippets.

@Gazer
Last active August 21, 2023 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gazer/372bae34bcd9cb0f30befd68b10ef44c to your computer and use it in GitHub Desktop.
Save Gazer/372bae34bcd9cb0f30befd68b10ef44c to your computer and use it in GitHub Desktop.
SwitftUI Lazy Staggered Vertical Grid
//
// LazyStaggedVGrid.swift
//
// Created by Ricardo Markiewicz on 20/08/2023.
// Copyright © 2023 orgName. No rights reserved.
//
// https://twitter.com/Gazeria/status/1693356336019333382
//
import SwiftUI
struct LazyStaggeredVGrid: Layout {
func sizeThatFits(
proposal: ProposedViewSize, // Size that is proposed to me
subviews: Subviews, // proxy to my childs (e.g. items)
cache: inout ()
) -> CGSize {
return proposal.replacingUnspecifiedDimensions()
}
func placeSubviews(
in bounds: CGRect, // Region where I need to place my subviews into
proposal: ProposedViewSize,
subviews: Subviews,
cache: inout ()
) {
var lastItemCol1: ViewSpacing? = nil
var lastItemCol2: ViewSpacing? = nil
let width = (proposal.width ?? 0) / 2
var col1 = 0.0
var col2 = 0.0
let childProposal = ProposedViewSize(width: width, height: nil)
subviews.enumerated().forEach({ (index, subview) in
let h = subview.sizeThatFits(childProposal).height
var spacingX: CGFloat = 0
if lastItemCol1 != nil {
spacingX = lastItemCol1!.distance(to: subview.spacing, along: .horizontal)
} else {
spacingX = subview.spacing.distance(to: subview.spacing, along: .horizontal)
}
var x = 0.0
var y = 0.0
if (col1 > col2) {
// Adding to Col2
let spacingY: CGFloat
if lastItemCol2 != nil {
spacingY = lastItemCol2!.distance(to: subview.spacing, along: .vertical)
} else {
spacingY = 0
}
// Coordinates
x = width + spacingX / 2
y = col2 + spacingY
// Finish
lastItemCol2 = subview.spacing
col2 += h + spacingY
} else {
// Adding to Col1
let spacingY: CGFloat
if lastItemCol1 != nil {
spacingY = lastItemCol1!.distance(to: subview.spacing, along: .vertical)
} else {
spacingY = 0
}
// Coordinates
y = col1 + spacingY
x = 0
// Finish
lastItemCol1 = subview.spacing
col1 += h + spacingY
}
let sizeProposal = ProposedViewSize(
width: width - spacingX / 2,
height: h
)
subview.place(at: CGPoint(x: x, y: y), proposal: sizeProposal)
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment