Read and update the scroll offset of a SwiftUI List
or ScrollView
from anywhere in the view hierarchy.
Use the scrollOffsetID
modifier to allow any child view to read the first scroll container's offset.
struct ContentView: View {
var body: some View {
ScrollView {
ChildView()
}
.overlay(ChildView())
.scrollOffsetID(.automatic)
}
}
Use ScrollOffset
to read the scroll offset from the provided edge. The scroll offset is calculated relative to any safe area insets.
struct ChildView: View {
@ScrollOffset(.top) private var scrollOffset
var body: some View {
Text(verbatim: "\(scrollOffset)")
}
}
Provide a range to ScrollOffset
to clamp the scroll offset. This prevents view updates for changes outside of this range.
@ScrollOffset(.top, in: -20...0) private var scrollOffset
Provide a unique identifier to scrollOffsetID
to read the scroll offset from anywhere in the view hierarchy.
Use the projectedValue
of ScrollOffset
to programmatically scroll to an offset.
struct ContentView: View {
var body: some View {
VStack {
ScrollView {
Rectangle()
.fill(.blue.opacity(0.1))
.frame(height: 1200)
}
.scrollOffsetID("Foo")
SiblingView()
.padding()
}
}
}
struct SiblingView: View {
@ScrollOffset(.top, id: "Foo") private var scrollOffset
var body: some View {
Text(verbatim: "\(scrollOffset)")
Button("Scroll to Top") {
$scrollOffset.scrollTo(.zero, withAnimation: true)
}
}
}
Use ScrollOffsetProxy
to read an offset, or programmatically scroll to an offset, without view updates when the offset changes.
struct ContentView: View {
@ScrollOffsetProxy(.bottom, id: "Foo") private var scrollOffsetProxy
var body: some View {
VStack {
List {
Section {
ForEach(0..<100) { number in
Text(verbatim: "\(number)")
}
}
}
.scrollOffsetID("Foo")
Button("Scroll to Bottom") {
scrollOffsetProxy.scrollTo(.zero, withAnimation: true)
}
.padding()
}
}
}
- iOS 14.0+, macOS 11.0+, tvOS 14.0+, visionOS 1.0+
- Xcode 15.0+
- Install with Swift Package Manager.
- Import
SwiftUIScrollOffset
to start using.
@ciaranrobrien on Twitter.