I\'ve been searching for a way to disable vertical bounce for a UIScrollView but only at bottom. I still need to have the bounce at the top.
Couldn\'t find anything.
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 UIScrollView
s that you don't want to alter their delegate (like UIWebView
's one).
Again, thanks go @0x7fffffff for the solution!
I have been looking a solution to disable bottom bounce only for a scrollview with wider contentSize width than device since I am using paging. None of those work for me but I found a way to do it. I thought I should share this since I wasted two days just to do this. I am using Swift 4 but this applies to objective c if you know how to convert this which should be easy if you have experience with both.
This works in a scrollview with device screen frame as frame.
Add variable to be aware for scrollview's current page.
var currentPage : Int!
Set initial value
currentPage = 0
Update currentPage
after scrolling
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let width = scrollView.frame.size.width
let page = (scrollView.contentOffset.x + (0.5 * width)) / width
currentPage = Int(page)
}
Filter bottom scrolling and update contentOffset
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if CGFloat(currentPage) * screenWidth < scrollView.contentOffset.x || CGFloat(currentPage) * screenWidth < scrollView.contentOffset.y || (((CGFloat(currentPage) * screenWidth - scrollView.contentOffset.x) >= 0) && scrollView.contentOffset.y > 0){
scrollView.contentOffset.y = 0
}
}
CGFloat(currentPage) * screenWidth < scrollView.contentOffset.x || CGFloat(currentPage) * screenWidth < scrollView.contentOffset.y
will filter bottom left and right scrolling
(((CGFloat(currentPage) * screenWidth - scrollView.contentOffset.x) >= 0) && scrollView.contentOffset.y > 0)
will filter bottom mid scrolling
scrollView.contentOffset.y = 0
will stop it from scrolling
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
}
}
Swift 3:
This works to disable vertical bounce only at the bottom:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.bounds.height {
scrollView.contentOffset.y = scrollView.contentSize.height - scrollView.bounds.height
}
}
Let's disable the bounces
when scroll to the bottom.
scrollView.bounces = scrollView.contentOffset.y < scrollView.contentSize.height - scrollView.frame.height
I added fabsf()
to 0x7fffffff♦'s solution to also cater for negative(downward) scroll:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (fabsf(scrollView.contentOffset.y) >= scrollView.contentSize.height - scrollView.frame.size.height) {
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, scrollView.contentSize.height - scrollView.frame.size.height)];
}
}