Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 911
Rey Gonzales Avatar asked Apr 03 '13 23:04

Rey Gonzales


1 Answers

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;
}
like image 80
Alessandro Orrù Avatar answered Sep 23 '22 08:09

Alessandro Orrù