How to detect Scrollview bounce - iOS
Asked Answered
N

3

16

I would like to implement "pull down to refresh" type effect on a UIScrollview. On detecting "top" bounce of the scrollview, the view should refresh some of the components. How can I detect the "top bounce" of UIScrollview? I tried the delegate "scrollViewWillBeginDragging" but did not work.

Nickolas answered 27/12, 2013 at 17:39 Comment(0)
E
18

Implement scrollViewDidScroll:, and check the value of scrollView.contentOffset.y -- it will be negative when you pull down, and go back to 0 (or near 0) when it bounces back. Depending on what condition you want to meet to do the refresh, you could set a flag when that value goes to a specific negative value, and then do the refresh when it goes back to near 0. Something like this:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.contentOffset.y < -50) _metNegativePullDown = YES;

    if (fabs(scrollView.contentOffset.y) < 1 && _metNegativePullDown) {
        //do your refresh here
        _metNegativePullDown = NO;
    }
}
Epic answered 27/12, 2013 at 17:53 Comment(3)
I'd suggest leaving out the second conditional, to mimic the behavior of UIRefreshControl, which users will be comfortable with. (Obviously, this is subjective.)Braynard
@AaronBrager, yeah, either way, depending on what the OP wants. I did it this way because he said he wanted to detect the bounce, and to me that means after it returns toward zero.Epic
While this approach works, i am not getting negative values in button-less devices like iPhoneX. Is it only me? or am I missing any other settings.Xhosa
B
13

For the record, i'm detecting both bounces on Swift 4 using this category:

extension UIScrollView {
    var isBouncing: Bool {
        var isBouncing = false
        if contentOffset.y >= (contentSize.height - bounds.size.height) {
            // Bottom bounce
            isBouncing = true
        } else if contentOffset.y < contentInset.top {
            // Top bounce
            isBouncing = true
        }
        return isBouncing
    }
}

Things to consider

  • In this case i'm just checking top content inset, if you are going to use bottom inset some tweaking must be necessary
  • If your scroll view is direct child of viewcontroller's view and has top constraint to superview instead of top safe area margin this will not do the trick perfect, more tweaking will be necessary
Basicity answered 7/11, 2018 at 13:59 Comment(0)
H
0

Most answers incorrectly handle the case when you scroll down. The main thing here is to use adjustedContentInset.bottom which includes both safeAreaInset and contentInset. Then it works correctly on iPhones with and without a notch.

extension UIScrollView {
    var isBottomBouncing: Bool {
        contentOffset.y > max(0.0, contentSize.height - bounds.height + adjustedContentInset.bottom)
    }
}

It is a very precise calculation, so if you rely on it in scrollViewDidScroll you may also need to apply some threshold, because scrollViewDidScroll may not catch the moment when isBottomBouncing changes to false.

Heterophyte answered 26/8, 2021 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.