Skip to content

Instantly share code, notes, and snippets.

@shnhrrsn
Last active December 19, 2022 05:40
Show Gist options
  • Save shnhrrsn/0df64c41c78ae63d188654d0c99bb1ee to your computer and use it in GitHub Desktop.
Save shnhrrsn/0df64c41c78ae63d188654d0c99bb1ee to your computer and use it in GitHub Desktop.
import SwiftUI
/// Implementation of `Layout` that aligns subviews relative it their `anchor` value
///
/// Considerations before using:
/// * Sizing is not taken into account
/// * No stacking is provided if multiple subviews are anchored to the same position
/// * Subviews will be able to overlap if anchored closely together and they're both large enough
public struct AnchorLayout: Layout {
public init() { }
public func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
proposal.replacingUnspecifiedDimensions()
}
public func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
for subview in subviews {
let anchor = subview[AnchorValue.self]
subview.place(
at: .init(
x: bounds.minX + (bounds.size.width * anchor.x),
y: bounds.minY + (bounds.size.height * anchor.y)
),
anchor: anchor,
proposal: proposal
)
}
}
}
private struct AnchorValue: LayoutValueKey {
static let defaultValue = UnitPoint.center
}
extension View {
public func anchor(_ anchor: UnitPoint) -> some View {
self.layoutValue(key: AnchorValue.self, value: anchor)
}
}
struct AnchorLayout_Previews: PreviewProvider {
static var previews: some View {
ZStack {
Color.yellow.frame(width: 5.0)
Color.yellow.frame(height: 5.0)
AnchorLayout {
Group {
Color.red.anchor(.topLeading)
Color.green.anchor(.top)
Color.blue.anchor(.topTrailing)
Color.pink.anchor(.leading)
Color.mint.anchor(.center)
Color.indigo.anchor(.trailing)
Color.orange.anchor(.bottomLeading)
Color.brown.anchor(.bottom)
Color.purple.anchor(.bottomTrailing)
Color.gray.anchor(.init(x: 0.25, y: 0.25))
}.frame(width: 50.0, height: 50.0).cornerRadius(20.0)
}.padding(5.0)
}
.frame(width: 300.0, height: 500.0)
.previewLayout(.sizeThatFits)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment