Last active
August 21, 2023 14:09
-
-
Save Gazer/372bae34bcd9cb0f30befd68b10ef44c to your computer and use it in GitHub Desktop.
SwitftUI Lazy Staggered Vertical Grid
This file contains hidden or 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
// | |
// 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