Skip to content

Instantly share code, notes, and snippets.

@khanlou
Last active April 26, 2024 05:05
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khanlou/112cbb13ee2c776aa343bfc204f78259 to your computer and use it in GitHub Desktop.
Save khanlou/112cbb13ee2c776aa343bfc204f78259 to your computer and use it in GitHub Desktop.
This ScrollView has a modifier called `onScroll`, which is updated when scrolls occur.
struct ContentView: View {
@State var scrollOffset: CGPoint = .zero
var body: some View {
ObservableScrollView {
Text("Hello, world!")
.foregroundColor(self.scrollOffset.y == 0 ? .blue : .red)
}
.onScroll { self.scrollOffset = $0 }
}
}
struct ScrollOffsetPreferenceKey: PreferenceKey {
typealias Value = CGPoint
static var defaultValue = CGPoint.zero
static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) {
value = nextValue()
}
}
struct ObservableScrollView<Content> : View where Content : View {
var content: Content
var axes: Axis.Set
var showsIndicators: Bool
init(_ axes: Axis.Set = .vertical, showsIndicators: Bool = true, @ViewBuilder content: () -> Content) {
self.content = content()
self.axes = axes
self.showsIndicators = showsIndicators
}
var body: some View {
GeometryReader { outerGeometry in
ScrollView(self.axes, showsIndicators: self.showsIndicators) {
ZStack(alignment: self.axes == .vertical ? .top : .leading) {
GeometryReader { innerGeometry in
Color.clear
.preference(key: ScrollOffsetPreferenceKey.self, value: CGPoint(x: (outerGeometry.frame(in: .global).minX - innerGeometry.frame(in: .global).minX), y: (outerGeometry.frame(in: .global).minY - innerGeometry.frame(in: .global).minY)))
}
VStack {
self.content
}
}
}
}
}
}
extension ObservableScrollView {
func onScroll(_ onScroll: @escaping (CGPoint) -> ()) -> some View {
self.onPreferenceChange(ScrollOffsetPreferenceKey.self, perform: onScroll)
}
}
@ForceGT
Copy link

ForceGT commented Mar 2, 2021

If anyone has been looking for a solution I found this really convenient to use
It has all kinds of customisation available, like making the scrollview a grid scrollview , tracking scroll offset putting a header, adjusting padding etc
It is a brilliant solution

@DmitriyTerekhin
Copy link

Wrong implementation of reduce func. Closure will not called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment