With SwiftUI 2.0 we can:
ScrollView() {
ScrollViewReader { proxy in
DummyContent()
.onTapGesture {
proxy.scroll(to: item...)
}
}
}
to scroll to a particular child inside a ScrollView.
I'm playing with 'from scratch' implementation of a ScrollView without using AppKit (custom implementation for the sake of learning and extending default ScrollView)
I managed to implement scrolling and clipping content in my ScrollViewer implementation, I want to implement scroll(to:), zoom(to:) functionality via ScrollViewerProxy like Apple did it with ScrollViewProxy. I can't figure out how Apple's ScrollViewProxy is able to manipulate parent view offset?
This is sample implementation of my ScrollViewerProxy and ScrollViewerReader:
struct ScrollViewerProxy {
@State var offset: CGSize = .zero
func scroll(to origin: CGPoint) {
let newOrigin = CGPoint(x: origin.x, y: origin.y)
offset = CGSize(width: newOrigin.x, height: newOrigin.y)
}
}
struct ScrollViewerReader<Content: View>: View {
let content: (ScrollViewerProxy) -> Content
@State private var offset: CGSize = .zero
private var scrollViewerProxy = ScrollViewerProxy()
init(@ViewBuilder _ content: @escaping (ScrollViewerProxy) -> Content) {
self.content = content
}
var body: some View {
content(scrollViewerProxy)
.offset( ??? ) // Can't do scrollViewerProxy.offset since it won't trigger ScrollViewerReader update
}
}
// Bellow is code from the custom ScrollView implementation, not so important, putting it here for for completeness' sake
struct ScrollViewer<Content: View>: View {
let content: Content
var body: some View {
ZStack {
GeometryReader { geometry
content
.offset(offset)
.onPreferenceChange(ContentPreferenceKey.self) { preferences in
guard let p = preferences.first else { fatalError() }
contentRect = p.frame
....
// I monitor content frame changes via PreferenceKey
}
}
}
}
}
// Usage:
ScrollViewer {
ScrollViewerReader { proxy in
DummyContent()
.onTapGesture {
let random = CGPoint(x: -Int.random(in: 0...400), y: 0)
proxy.scroll(to: random)
}
}
}