How can I test if the scroll view is bouncing?
Asked Answered
A

7

17

How can I test if the scroll view is bouncing? Is there a notification or something when the bounce ends?

Ashlieashlin answered 18/5, 2010 at 0:44 Comment(0)
N
7

Yes... check out the UIScrollViewDelegate spec, implement the methods including the two below, and set your UIScrollView's delegate accordingly:

// User stops dragging the table view.

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

// Control slows to a halt after the user drags it

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

You will probably be most interested in scrollViewDidEndDecelerating. These also work in UITableView which is where I originally found them (UITableView inherits from UIScrollView).

Nonperishable answered 18/5, 2010 at 4:43 Comment(1)
Thanks a lot. I know this way, I just thought that there is an other method. Thanks! :)Ashlieashlin
S
34

Here is how I detected if the scroll view is bouncing horizontally:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

  if (scrollView.contentOffset.x < 0) {
    NSLog(@"bouncing left");
  }

  if (scrollView.contentOffset.x > (scrollView.contentSize.width - scrollView.frame.size.width)) {
    NSLog(@"bouncing right");
  }
}
Squirm answered 26/1, 2012 at 22:23 Comment(0)
T
29

I've implemented extension for UIScrollView to handle this for vertical and horizontal scrolling. This will work even with non-zero contentInsets and in case when content is not big enough for covering scrollView insets:

Objective-C

@interface UIScrollView (Bouncing)

@property (nonatomic, readonly) BOOL isBouncing;
@property (nonatomic, readonly) BOOL isBouncingTop;
@property (nonatomic, readonly) BOOL isBouncingLeft;
@property (nonatomic, readonly) BOOL isBouncingBottom;
@property (nonatomic, readonly) BOOL isBouncingRight;

@end

@implementation UIScrollView (Bouncing)

- (BOOL)isBouncing
{
    return self.isBouncingTop || self.isBouncingLeft || self.isBouncingBottom || self.isBouncingRight;
}

- (BOOL)isBouncingTop
{
    return self.contentOffset.y < - self.contentInset.top;
}

- (BOOL)isBouncingLeft
{
    return self.contentOffset.x < - self.contentInset.left;
}

- (BOOL)isBouncingBottom
{
    BOOL contentFillsScrollEdges = self.contentSize.height + self.contentInset.top + self.contentInset.bottom >= CGRectGetHeight(self.bounds);
    return contentFillsScrollEdges && self.contentOffset.y > self.contentSize.height - CGRectGetHeight(self.bounds) + self.contentInset.bottom;
}

- (BOOL)isBouncingRight
{
    BOOL contentFillsScrollEdges = self.contentSize.width + self.contentInset.left + self.contentInset.right >= CGRectGetWidth(self.bounds);
    return contentFillsScrollEdges && self.contentOffset.x > self.contentSize.width - CGRectGetWidth(self.bounds) + self.contentInset.right;
}

@end

Swift 3.0+

extension UIScrollView {
  var isBouncing: Bool {
    return isBouncingTop || isBouncingLeft || isBouncingBottom || isBouncingRight
  }
  var isBouncingTop: Bool {
    return contentOffset.y < -contentInset.top
  }
  var isBouncingLeft: Bool {
    return contentOffset.x < -contentInset.left
  }
  var isBouncingBottom: Bool {
    let contentFillsScrollEdges = contentSize.height + contentInset.top + contentInset.bottom >= bounds.height
    return contentFillsScrollEdges && contentOffset.y > contentSize.height - bounds.height + contentInset.bottom
  }
  var isBouncingRight: Bool {
    let contentFillsScrollEdges = contentSize.width + contentInset.left + contentInset.right >= bounds.width
    return contentFillsScrollEdges && contentOffset.x > contentSize.width - bounds.width + contentInset.right
  }
}

For RxSwift you can just map scrollViewDidScroll with isBouncing and filter with distinctUntilChanged.

Triphthong answered 22/3, 2017 at 12:5 Comment(0)
A
9

A minor amendment to Justin's method, allowing for contentInset:

if( scrollView.contentOffset.x < -scrollView.contentInset.left )
{
    NSLog( @"bounce left" );
}
if( scrollView.contentOffset.x > scrollView.contentSize.width - scrollView.frame.size.width + scrollView.contentInset.right )
{
    NSLog( @"bounce right" );
}
Arda answered 22/11, 2012 at 11:17 Comment(0)
N
7

Yes... check out the UIScrollViewDelegate spec, implement the methods including the two below, and set your UIScrollView's delegate accordingly:

// User stops dragging the table view.

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

// Control slows to a halt after the user drags it

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

You will probably be most interested in scrollViewDidEndDecelerating. These also work in UITableView which is where I originally found them (UITableView inherits from UIScrollView).

Nonperishable answered 18/5, 2010 at 4:43 Comment(1)
Thanks a lot. I know this way, I just thought that there is an other method. Thanks! :)Ashlieashlin
Q
3

Old question but I just ran into a similar issue and wanted to add that it is a good idea to also check that the scroll views content is larger than the scroll view's frame:

+ (BOOL) isScrollViewBouncing:(UIScrollView *)scrollView
{
    return scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.frame.size.height
            && scrollView.contentSize.height > scrollView.frame.size.height;
}

This now makes sure the scroll view is large enough to be in a scroll-bouncing state, so that if the scroll view is small it does NOT always evaluate to true.

Cheers

Quod answered 15/1, 2014 at 22:58 Comment(0)
N
1

For those of you who would be able to "bounce" downwards in a scrollview in order to update contents of the view. (And the event is only fired once.)

- (void)scrollViewDidEndDragging:(UIScrollView *)aScrollView
                  willDecelerate:(BOOL)decelerate{

    CGPoint offset = aScrollView.contentOffset;
    CGRect bounds = aScrollView.bounds;
    CGSize size = aScrollView.contentSize;
    UIEdgeInsets inset = aScrollView.contentInset;
    float y = offset.y + bounds.size.height - inset.bottom;
    float h = size.height;

    //Distance in points before update-event occur
    float reload_distance = 50;
    //
    if(y > h + reload_distance) {
        NSLog(@"load more rows");
    }
}
Neoplasm answered 25/7, 2013 at 14:2 Comment(0)
D
0

Using Glavid's answer, I added bouncing to bottom also, and added as a category

#import "UIScrollView+Additions.h"

@implementation UIScrollView (Additions)

- (BOOL)isBouncing
{
    BOOL isBouncingBottom = self.contentOffset.y >= self.contentSize.height - self.frame.size.height
        && self.contentSize.height >= self.frame.size.height;
    BOOL isBouncingTop = self.contentOffset.y <= 0;

    BOOL isBouncing = isBouncingBottom || isBouncingTop;
    return isBouncing;
}

@end
Discriminator answered 23/3, 2016 at 11:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.