Skip to content

Instantly share code, notes, and snippets.

@shaps80
Created November 12, 2024 14:31
Show Gist options
  • Save shaps80/f063fb32540ec4cc56f90e2e7989faa3 to your computer and use it in GitHub Desktop.
Save shaps80/f063fb32540ec4cc56f90e2e7989faa3 to your computer and use it in GitHub Desktop.
import SwiftUI
public extension View {
func onGeometryChange<T>(
for type: T.Type,
of transform: @escaping (GeometryProxy) -> T,
action: @escaping (_ newValue: T) -> Void
) -> some View where T: Equatable {
modifier(GeometryModifier(transform: transform, action: action))
}
}
private struct GeometryModifier<T: Equatable>: ViewModifier {
var transform: (GeometryProxy) -> T
var action: (T) -> Void
func body(content: Content) -> some View {
content
.background {
GeometryReader { proxy in
Color.clear
.preference(key: GeometryPreferenceKey.self, value: .init(proxy: proxy))
}
}
.onPreferenceChange(GeometryPreferenceKey.self) { geo in
if let geo {
action(transform(geo.proxy))
}
}
}
}
private struct GeometryPreferenceKey: PreferenceKey {
nonisolated(unsafe) static let defaultValue: Geometry? = nil
static func reduce(value: inout Geometry?, nextValue: () -> Geometry?) {
value = nextValue()
}
}
private struct Geometry: Equatable {
var proxy: GeometryProxy
static func == (lhs: Geometry, rhs: Geometry) -> Bool {
(lhs.proxy.size, lhs.proxy.safeAreaInsets)
== (rhs.proxy.size, rhs.proxy.safeAreaInsets)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment