UIScrollView disable vertical bounce only at bottom UIScrollView disable vertical bounce only at bottom ios ios

UIScrollView disable vertical bounce only at bottom


Use the UIScrollViewDelegate method scrollViewDidScroll to check the content offset of the scrollview and more or less check if the user is trying to scroll beyond the bottom bounds of the scroll view. Then just use this to set the scroll back to the end of the scroll view. It happens so rapidly that you can't even tell that the scroll view bounced or extended beyond its bounds at all.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {    if (scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.size.height) {        [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, scrollView.contentSize.height - scrollView.frame.size.height)];    }}


To disable vertical bounce at the top in Swift:

func scrollViewDidScroll(scrollView: UIScrollView) {    if scrollView.contentOffset.y < 0 {        scrollView.contentOffset.y = 0    }}

To disable vertical bounce at the bottom in Swift:

func scrollViewDidScroll(_ scrollView: UIScrollView) {    if scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.bounds.height {        scrollView.contentOffset.y = scrollView.contentSize.height - scrollView.bounds.height    }}


Based on 0x7fffffff's answer I've created a class:

VerticalBounceControl.h

#import <UIKit/UIKit.h>@interface VerticalBounceControl : NSObject@property (nonatomic, assign) BOOL bounce;- (id) initWithScrollView:(UIScrollView*)scrollView bounceAtTop:(BOOL)bounceAtTop bounceAtBottom:(BOOL)bounceAtBottom;@end

VerticalBounceControl.m

#import "VerticalBounceControl.h"@interface VerticalBounceControl ()@property (nonatomic, retain) UIScrollView* scrollView;@property (nonatomic, assign) BOOL bounceAtTop;@property (nonatomic, assign) BOOL bounceAtBottom;@end@implementation VerticalBounceControl- (id) initWithScrollView:(UIScrollView*)scrollView bounceAtTop:(BOOL)bounceAtTop bounceAtBottom:(BOOL)bounceAtBottom {    self = [super init];    if(self) {        self.bounce = YES;        self.scrollView = scrollView;        self.bounceAtTop = bounceAtTop;        self.bounceAtBottom = bounceAtBottom;        [self.scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:NULL];    }    return self;}- (void) dealloc {    [self.scrollView removeObserver:self forKeyPath:@"contentOffset"];    self.scrollView = nil;}- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {    if ([keyPath isEqualToString:@"contentOffset"]) {        if (self.bounce && ((self.scrollView.contentOffset.y<=0 && self.bounceAtTop) || (self.scrollView.contentOffset.y>=self.scrollView.contentSize.height-1 && self.bounceAtBottom))) {            self.scrollView.bounces = YES;        } else {            self.scrollView.bounces = NO;        }    }}@end

that can be used without the caller being a delegate of UIScrollView like this:

VerticalBounceControl* bounceControl = [[VerticalBounceControl alloc] initWithScrollView:anyScrollView bounceAtTop:YES bounceAtBottom:NO];

This way you can have this bounce behavior for UIScrollViews that you don't want to alter their delegate (like UIWebView's one).

Again, thanks go @0x7fffffff for the solution!


matomo