0
votes

I need to have a scrollview with a slightly different behaviour than the UIKit one.

What I'd like to obtain is a paged scrollview, but I'd like to use some custom values for the amount of scroll the user must do to trigger the paging.

Looks like the system UIScrollView trigger the page change when the user scrolls for more than 50% of the current page. I'd like to make it "harder" for the user to switch page.

Additionally the system UIScrollView takes into account the velocity of the gesture, so if the user scroll very few pixels but with a quite fast gesture, the page get switched, which I'd like to avoid.

1
Have you tried to implement this? I'm sure it could be done using a non-paged table view, and looking at the content offset in scrollViewDidScroll.rdelmar
Just asking, but why a TableView? Could I use the same approach with a non-paged scrollview by watching at the same delegate method?Axy
Sorry, that was a typo. I meant scroll view. And, actually, you probably want to look at the offset in scrollViewDidEndDragging:willDecelerate:, and decide there whether to go on to the next page or go back.rdelmar
It worked, I will post the code in the answer. Thanks for the tip.Axy

1 Answers

0
votes

Ok, I implemented it this way and it works quite well:

//this is the percentage of page I need to drag to trigger the paging
#define PAGING_THREESHOLD 0.6

//this enum is to keep track of the scrolling direction
typedef enum ScrollDirection {
    ScrollDirectionNone,
    ScrollDirectionRight,
    ScrollDirectionLeft,
    ScrollDirectionUp,
    ScrollDirectionDown,
    ScrollDirectionCrazy,
} ScrollDirection;

//this is to avoid the intertial scrolling
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                 withVelocity:(CGPoint)velocity
          targetContentOffset:(inout CGPoint *)targetContentOffset {
    *targetContentOffset = scrollView.contentOffset;
}

//here is the custom paging code
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{

    CGPoint destinationOffset = scrollView.contentOffset;
    CGFloat y = (int)destinationOffset.y % (int)scrollView.height;

    if (_scrollDirection == ScrollDirectionDown){
        CGFloat delta = scrollView.height - (scrollView.height - y);
        delta = delta / scrollView.height;
        NSUInteger currentPage = scrollView.contentOffset.y / scrollView.size.height;
        if (delta > PAGING_THREESHOLD && currentPage != scrollView.verticalPageCount - 1){
            //go to next page
            destinationOffset = CGPointMake(destinationOffset.x, (currentPage + 1) * scrollView.height);
        }else{
            destinationOffset = CGPointMake(destinationOffset.x, currentPage * scrollView.height);
        }
    }else if (_scrollDirection == ScrollDirectionUp){
        CGFloat delta = scrollView.height - y;
        delta = delta / scrollView.height;
        NSUInteger currentPage = scrollView.contentOffset.y / scrollView.size.height;
        if (delta > PAGING_THREESHOLD){
            //go to next page
            destinationOffset = CGPointMake(destinationOffset.x, currentPage * scrollView.height);
        }else{
            destinationOffset = CGPointMake(destinationOffset.x, (currentPage + 1) * scrollView.height);
        }
    }
    if (!CGPointEqualToPoint(destinationOffset, scrollView.contentOffset)){
        [scrollView setContentOffset:destinationOffset animated:YES];
    }
}

//here the scrolldirection is calculated
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (self.lastContentOffset.x > scrollView.contentOffset.x){
        _scrollDirection = ScrollDirectionRight;
    } else if (self.lastContentOffset.x < scrollView.contentOffset.x){
        _scrollDirection = ScrollDirectionLeft;
    } else if (self.lastContentOffset.y > scrollView.contentOffset.y){
        _scrollDirection = ScrollDirectionUp;
    } else if (self.lastContentOffset.y < scrollView.contentOffset.y){
        _scrollDirection = ScrollDirectionDown;
    } else{
        _scrollDirection = ScrollDirectionNone;
    }
    self.lastContentOffset = scrollView.contentOffset;
}