How to know exactly when a UIScrollView's scrolling has stopped?

后端 未结 6 1023
慢半拍i
慢半拍i 2020-12-04 22:07

In short, I need to know exactly when the scrollview stopped scrolling. By \'stopped scrolling\', I mean the moment at which it is no longer moving and not being touched.

相关标签:
6条回答
  • 2020-12-04 22:31

    Delegate methods mentioned in this post answers did not help me. I found another answer which detect final scroll end in scrollViewDidScroll: Link is here

    0 讨论(0)
  • 2020-12-04 22:33

    I answered this question on my blog which outlines how to do it without problems.

    It involves 'intercepting the delegate' to do a few things, then to pass the delegate messages to where they were intended. This is required because there are a few scenarios where the delegate fires if it moved programmatically, or not, or both, and so anyway, best to just look at this link below:

    How to know when a UIScrollView is scrolling

    It's a little tricky, but I've put up a recipe there and have explained the parts in detail.

    0 讨论(0)
  • 2020-12-04 22:33

    It is important to understand, that the when UIScrollView is stopping to move it triggers two different functions of the UIScrollViewDelegate depending on how strong the user has pushed.

    1. stopDragging is triggered, when the user stops his drag gesture on the screen. When this was very slowly no more movement will happen after that.
    2. stopDecelerating is triggered, when the user has pushed the scroll view in a way, so that it is still moving after the user touches up his finger and then comes to an end. This function is not always triggered, it is not triggered, when there is no movement after the user touches up his finger. Then only the function above "stopDragging" is triggered.

    So in conclusion it is necessary to combine the two functions like @WayneBurkett already pointed out in his answer.

    In Swift 5.X:

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        myFunction()
    }
    
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if decelerate == false {
            myFunction()
        }
    }
    
    private func myFunction() {
        // scrollView did stop moving -> do what ever
        // ...
    }
    
    0 讨论(0)
  • 2020-12-04 22:44

    [Edited Answer] This is what I use - it handles all the edge cases. You need an ivar to keep state, and as shown in the comments, there are other ways to handle this.

    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
        //[super scrollViewWillBeginDragging:scrollView];   // pull to refresh
    
        self.isScrolling = YES;
        NSLog(@"+scrollViewWillBeginDragging");
    }
    
    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    {
        //[super scrollViewDidEndDragging:scrollView willDecelerate:decelerate];    // pull to refresh
    
        if(!decelerate) {
            self.isScrolling = NO;
        }
        NSLog(@"%@scrollViewDidEndDragging", self.isScrolling ? @"" : @"-");
    }
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        self.isScrolling = NO;
        NSLog(@"-scrollViewDidEndDecelerating");
    }
    
    - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
    {   
        self.isScrolling = NO;
        NSLog(@"-scrollViewDidScrollToTop");
    }
    
    - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
    {
        self.isScrolling = NO;
        NSLog(@"-scrollViewDidEndScrollingAnimation");
    }
    

    I created a really simple project uses the above code, so that when a person interacts with a scrollView (including a WebView), it inhibits process intensive work until the user stops interacting with the scrollView AND the scrollview has stopped scrolling. It's like 50 lines of code: ScrollWatcher

    0 讨论(0)
  • 2020-12-04 22:51

    Here's how to combine scrollViewDidEndDecelerating and scrollViewDidEndDragging:willDecelerate to perform some operation when scrolling has finished:

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        [self stoppedScrolling];
    }
    
    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
                      willDecelerate:(BOOL)decelerate
    {
        if (!decelerate) {
            [self stoppedScrolling];
        }
    }
    
    - (void)stoppedScrolling
    {
        // done, do whatever
    }
    
    0 讨论(0)
  • 2020-12-04 22:56

    I found a solution:

    -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    

    I did not notice that last bit before, willDecelerate. It is false when the scrollView is stationary when ending the touch. Combined with the above-mentioned speed check, I can snap both when it's slow (and not being touched) or when it's stationary.

    For anyone not doing any snapping but needs to know when scrolling stopped, didEndDecelerating will be called at the end of the scroll movement. Combined with a check on willDecelerate in didEndDragging, you'll know when the scrolling has stopped.

    0 讨论(0)
提交回复
热议问题