I’ve a SwiftUI ScrollView
for which I wish to carry out particular actions on scrolling and particularly when determining the scroll route.
That is my arrange to determine the scroll route:
ScrollView {
content material
.background(scrollDirectionTrackerView)
.onPreferenceChange(ScrollOffsetKey.self) { updatedOffset in
updateScrollDirection(updatedOffset)
}
}
.coordinateSpace(title: "scrollView")
personal var scrollDirectionTrackerView: some View {
GeometryReader { proxy in
Colour.clear.desire(key: ScrollOffsetKey.self,
worth: -proxy.body(in: .named(coordinateSpaceKey)).origin.y)
}
}
In case you see my code, I’ve the perform updateScrollDirection
known as which is used to course of which route the consumer is scrolling in:
// Someplace throughout the View
personal let minimumDirectionChangeOffset = 16.0
personal var scrollDirectionUpdateHandler: ((ScrollDirection) -> Void)?
@State personal var currentDirection = ScrollDirection.none
@State personal var previousScrollOffset = CGFloat.zero
personal func updateScrollDirection(_ newOffset: CGFloat) {
let offsetDifference = previousScrollOffset - newOffset
var updatedDirection = currentDirection
if abs(offsetDifference) > minimumDirectionChangeOffset {
if offsetDifference > 0 {
updatedDirection = axis == .vertical ? .up : .backward
} else {
updatedDirection = axis == .vertical ? .down : .ahead
}
previousScrollOffset = newOffset
}
// Solely publish if now we have a distinct route
if updatedDirection != currentDirection {
currentDirection = updatedDirection
scrollDirectionUpdateHandler?(currentDirection) // The subscriber performs an animation
}
}
For essentially the most half this works properly. I wish to draw your consideration to the final line which is the place I write an animation occurs solely when the route adjustments.
If I carry out the scroll quick in both route, this works properly.
Nevertheless, once I drag actually slowly, I really feel both a race situation occurs with a number of threads accessing this perform or or one thing else, however the route will get set a number of instances triggering a number of animations which ends up in a uneven consumer expertise as a result of an animation being in progress.
I’m questioning if there’s a extra elegant strategy to deal with this:
- with a debounce of some kinds
- some form of semaphore / lock such that we will lock the perform
- or higher math even ?
Another concepts that come to is a Bool variable to lock the perform however hoped for one thing extra elegant.
The animation to be carried out is the hiding / displaying of a UIKit based mostly View so the animation that occurs is a UIView.animate
block that has a 0.5 period.
I attempted this outdated reply however it didn’t assist me.
Is there a greater strategy to stop the gradual drag from altering the scroll route a number of instances ?
Lastly, I have to assist iOS 16+.