Skip to content

Instantly share code, notes, and snippets.

@yannxou
Created September 28, 2023 12:58
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 yannxou/b7d38c448de6b78d5bab2ee588ef848c to your computer and use it in GitHub Desktop.
Save yannxou/b7d38c448de6b78d5bab2ee588ef848c to your computer and use it in GitHub Desktop.
SwiftUI: ScrollToModifier
import SwiftUI
public struct ScrollToModifier<T: Hashable>: ViewModifier {
@Binding var id: T?
public func body(content: Content) -> some View {
ScrollViewReader { proxy in
content
.onChange(of: id) { newValue in
if let id {
scrollTo(id: id, using: proxy)
}
}
.onAppear {
if let id {
// allow time to draw contents first (otherwise scroll position can fail)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
scrollTo(id: id, using: proxy)
}
}
}
}
}
private func scrollTo(id: T, using proxy: ScrollViewProxy) {
withAnimation {
proxy.scrollTo(id, anchor: .top)
self.id = nil
}
}
}
public extension View {
/// Automatically adds support for scrolling to the view matching the `id` provided by the given binding.
///
/// When the binding has an initial value the modified view will automatically scroll to the view with that id when it first appears.
/// While the view is presented any change to the binding also makes the scroll move to the new id position.
///
/// The binding is automatically set to `nil` once the scroll has been performed.
///
/// **Note** that the modified view must be part of a ScrollView or List in order to support scrolling. This modifier does not add any scroll, it just reads from its ScrollViewProxy and updates it accordingly.
/// - Parameter id: A binding property to the id used to identify the view.
/// - Returns:
func scrollTo<T: Hashable>(id: Binding<T?>) -> some View {
modifier(ScrollToModifier(id: id))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment