Reputation: 145
There was, by all accounts, an excellent solution to this problem in Obj-C presented by Ashley Smart (How to detect when a UIScrollView has finished scrolling).
-(void)scrollViewDidScroll:(UIScrollView *)sender
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
//ensure that the end of scroll is fired.
[self performSelector:@selector(scrollViewDidEndScrollingAnimation:) withObject:nil afterDelay:0.3];
...
}
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
...
}
I need a solution, however, in Swift.
It appears that the excellent delay function, contributed by Matt (dispatch_after - GCD in swift?) is likely to help.
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
and implemented as ...
delay(0.4) {
// do stuff
}
but I've still not put it together. Any help?
Upvotes: 14
Views: 27552
Reputation: 934
The delegate method tells you when finished
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
self.stoppedScrolling()
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.stoppedScrolling()
}
}
func stoppedScrolling() {
println("Scroll finished")
}
Upvotes: 32
Reputation: 669
You need to check whether the user has stopped dragging and if the view is still decelerating after the user stopped dragging:
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if collectionView.isDecelerating == false {
// Perform whichever function you desire for when scrolling has stopped
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Perform whichever function you desire for when scrolling has stopped
}
Upvotes: 4
Reputation: 3718
Swift Version:
NOTE: The answer you mentioned is a possible solution and differ with cases
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// YOUR CODE........
NSObject.cancelPreviousPerformRequests(withTarget: self)
self.perform(#selector(scrollViewDidEndScrollingAnimation(_:)), with: scrollView, afterDelay: 0.3)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
// YOUR CODE ........
NSObject.cancelPreviousPerformRequests(withTarget: self)
}
Upvotes: 0
Reputation: 61
There is a method of UIScrollViewDelegate
which can be used to detect (or better to say 'predict') when scrolling has really finished:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
of UIScrollViewDelegate
which can be used to detect (or better to say 'predict') when scrolling has really finished.
In my case I used it with horizontal scrolling as following (in Swift 3):
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
perform(#selector(self.actionOnFinishedScrolling), with: nil, afterDelay: Double(velocity.x))
}
func actionOnFinishedScrolling() {
print("scrolling is finished")
// do what you need
}
Upvotes: 5
Reputation: 1736
The scrollViewDidEndDecelerating
won't be called if user is scrolling slowly. Here's Ashley Smart asnwear in Swift
func scrollViewDidScroll(_ scrollView: UIScrollView) {
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), with: nil, afterDelay: 0.3)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
NSObject.cancelPreviousPerformRequests(withTarget: self)
// Call your function here
}
Upvotes: 11