Skip to content

Instantly share code, notes, and snippets.

@darrarski
Last active January 16, 2022 23:27
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 darrarski/d837d8d838cdc175e8730cc0a27d82af to your computer and use it in GitHub Desktop.
Save darrarski/d837d8d838cdc175e8730cc0a27d82af to your computer and use it in GitHub Desktop.
SwiftUI extension that attaches geometry reader to a view and notifies whenever provided geometry changes.
import SwiftUI
extension View {
func geometryReader<Geometry: Codable>(
geometry: @escaping (GeometryProxy) -> Geometry,
onChange: @escaping (Geometry) -> Void
) -> some View {
modifier(GeometryReaderViewModifier(
geometry: geometry,
onChange: onChange
))
}
}
struct GeometryReaderViewModifier<Geometry: Codable>: ViewModifier {
var geometry: (GeometryProxy) -> Geometry
var onChange: (Geometry) -> Void
func body(content: Content) -> some View {
content
.background {
GeometryReader { geometryProxy in
Color.clear
.preference(key: GeometryPreferenceKey.self, value: {
let geometry = self.geometry(geometryProxy)
let data = try? JSONEncoder().encode(geometry)
return data
}())
.onPreferenceChange(GeometryPreferenceKey.self) { data in
if let data = data,
let geomerty = try? JSONDecoder().decode(Geometry.self, from: data)
{
onChange(geomerty)
}
}
}
}
}
}
struct GeometryPreferenceKey: PreferenceKey {
static var defaultValue: Data? = nil
static func reduce(value: inout Data?, nextValue: () -> Data?) {
value = nextValue()
}
}
#if DEBUG
struct GeometryReaderModifier_Previews: PreviewProvider {
struct Preview: View {
@State var size: CGSize = .zero
var body: some View {
VStack {
Text("Hello, World!")
.font(.largeTitle)
.background(Color(.secondarySystemBackground))
.geometryReader(
geometry: \.size,
onChange: { size = $0 }
)
Text("\(Int(size.width.rounded())) x \(Int(size.height.rounded()))")
.font(.caption)
.frame(width: size.width, height: size.height)
.background(Color(.secondarySystemBackground))
}
}
}
static var previews: some View {
Preview()
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment