iosuitableviewcocoa-touchpaginationuiscrollview

UIScrollView - Revert to starting position without snaps


I want to revert my UIScrollView's content offset if I don't drag enough:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(CGPoint *)targetContentOffset {
    self.endingOffset = scrollView.contentOffset;

    if(abs(verticalOffset) > [self cellHeight] / 9) { // If the user scrolled enough distance, attempt to scroll to the next cell
        ...
    } else if(self.nextCellOrigin.y != 0) { // The scroll view is still scrolling and the user didn't drag enough
        ...
    } else { // If the user didn't drag enough
        self.tableView.decelerationRate = UIScrollViewDecelerationRateNormal;
        (*targetContentOffset) = self.startingOffset;
    }
}

The code to revert to the original position is in the else portion, and it always works. However, when I don't scroll enough and make the gesture quickly, it snaps back. If I scroll just a little and then hold that position for slightly longer than usual, it reverts back smoothly.

I haven't found anything in the API reference for how long a user has touched a UIScrollView, and even if I did it's not immediately obvious how I could use that to change the behavior of my reverting code. I've also tried scrolling to the position with setContentOffset:animated: but that doesn't seem to fix the jerkiness.

Any ideas?


Solution

  • Have you tried logging the velocity to find out how it is when the jerkiness happens?

    EDIT:

    What you can try to do is implement these two scrollView delegate methods instead of the willEndDragging method. This solution will give a different feeling to the scrollView, but give it a try.

    Fill the checkOffset method with all the logic you need.

    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    
        // if scrollView's contentOffset reached its final position during scroll, it will not decelerate, so you need a check here too
        if (!decelerate) {
           [self checkOffset];
        }
    }    
    
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
       [self checkOffset];
    }
    
    
    - (void)checkOffset {
        CGPoint newOffset;
        ...
        // Do all the logic you need to move the content offset, then:
        ...
        [self.scrollView setContentOffset:newOffset animated:YES];
    }
    

    EDIT #2: Maybe you could achieve a better result if you also add this to my solution.. Try ;)

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(CGPoint *)targetContentOffset {
        // This should force the scrollView to stop its inertial deceleration, by forcing it to stop at the current content offset
        *targetContentOffset = scrollView.contentOffset;
    }