Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView does not always animate deceleration when overriding scrollViewWillEndDragging

I am creating custom paging for my UICollectionView. I want some of the cells at the bottom to hang off of the edge of the screen, however, with regular paging, scrolling to the next page means that if half of the cell at the bottom of the page was showing, it will only show the other half on the next page. I want to let the cells hang off of the end, but stop the paging so that the cells hanging off of the screen are in clear view.

So, to do this I overrode the function - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

If I drag for a second or two, it sees to work as expected, however, I am trying to emulate the "flick" that works so well when paging is enabled. When I flick my UICollectionView, it jumps to the targetContentOffset, rather than animates to it.

How do I prevent this?

Here is my code:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {

    if(targetContentOffset->y < 400) {
        targetContentOffset->y = 0;
        return;
    }

    int baseCheck = 400;

    while(baseCheck <= 10000) {
        if(targetContentOffset->y > baseCheck && targetContentOffset->y < baseCheck + 800) {
            targetContentOffset->y = (baseCheck + 340);
            return;
        }
        baseCheck += 800;
    }

    targetContentOffset->y = 0;
}
like image 662
3rdFunkyBot Avatar asked Jan 15 '23 01:01

3rdFunkyBot


2 Answers

I came across the same issue and managed to work it around. In my case I am simulating a paginated scrollView (which is actually a UICollectionView) where the page size is smaller than the size of the collectionView itself. I noticed that the 'jumping' of the scroll happens under a certain set of conditions:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    CGFloat pageWidth; // defined somewhere else
    NSInteger numberOfPages; // depends on your dataSource
    CGFloat proposedOffset = targetContentOffset->x;
    NSInteger currentPage = roundf(self.collectionView.contentOffset.x / pageWidth);
    NSInteger proposedPage = roundf(proposedOffset / pageWidth);
    // what follows is a fix for a weird case where the scroll 'jumps' into place with no animation
    if(currentPage == proposedPage) {
        if((currentPage == 0 && velocity.x > 0) ||
           (currentPage == (numberOfPages - 1) && velocity.x < 0) ||
           (currentPage > 0 && currentPage < (numberOfPages - 1) && fabs(velocity.x) > 0)
           ) {
            // this forces the scrolling animation to stop in its current place
            [self.collectionView setContentOffset:self.collectionView.contentOffset animated:NO];
            [UIView animateWithDuration:.3
                                  delay:0.
                                options:UIViewAnimationOptionCurveEaseOut
                             animations:^{
                                 [self.collectionView setContentOffset:CGPointMake(currentPage * pageWidth, 0)];
                             }
                             completion:NULL];
        }
    }
    targetContentOffset->x = (pageWidth * proposedPage);
}
like image 190
boliva Avatar answered Apr 28 '23 07:04

boliva


It 'jumps' directly to targetContentOffset because it uses the velocity given. And a flick has a very high velocity. You should check the value of velocity, and if superior to a certain rate (around 2 I think but you can adjust) then you do the animation yourself (with a simple [scrollView setContentOffset:contentOffset animated:YES];

like image 24
Aymarick Avatar answered Apr 28 '23 08:04

Aymarick