How to make an UICollectionView with infinite paging?

Burak picture Burak · Nov 27, 2012 · Viewed 7.9k times · Source

I have a UICollectionView with 6 pages, and paging enabled, and a UIPageControl. What I want is, when I came to the last page, if I drag to right, UICollectionView reloads from first page seamlessly.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender
{

// The key is repositioning without animation
if (collectionView.contentOffset.x == 0) {
    // user is scrolling to the left from image 1 to image 10.
    // reposition offset to show image 10 that is on the right in the scroll view
    [collectionView scrollRectToVisible:CGRectMake(collectionView.frame.size.width*(pageControl.currentPage-1),0,collectionView.frame.size.width,collectionView.frame.size.height) animated:NO];
}
else if (collectionView.contentOffset.x == 1600) {
    // user is scrolling to the right from image 10 to image 1.
    // reposition offset to show image 1 that is on the left in the scroll view
    [collectionView scrollRectToVisible:CGRectMake(0,0,collectionView.frame.size.width,collectionView.frame.size.height) animated:NO];

}
pageControlUsed = NO;

}

It doesn't work like I want. What can I do?

Answer

Gujamin picture Gujamin · Jan 11, 2013

Here's what I ended up with for my UICollectionView (horizontal scrolling like the UIPickerView):

@implementation UIInfiniteCollectionView

- (void) recenterIfNecessary {
    CGPoint currentOffset = [self contentOffset];
    CGFloat contentWidth = [self contentSize].width;
    // don't just snap to center, since this might be done in the middle of a drag and not aligned.  Make sure we account for that offset
    CGFloat offset = kCenterOffset - currentOffset.x;
    int delta = -round(offset / kCellSize);
    CGFloat shift = (offset + delta * kCellSize);
    offset += shift;
    CGFloat distanceFromCenter = fabs(offset);

    // don't always recenter, just if we get too far from the center.  Eliza recommends a quarter of the content width
    if (distanceFromCenter > (contentWidth / 4.0)) {
        self.contentOffset = CGPointMake(kCenterOffset, currentOffset.y);
        // move subviews back to make it appear to stay still
        for (UIView *subview in self.subviews) {
            CGPoint center = subview.center;
            center.x += offset;
            subview.center = center;
        }
        // add the offset to the index (unless offset is 0, in which case we'll assume this is the first launch and not a mid-scroll)
        if (currentOffset.x > 0) {
            int delta = -round(offset / kCellSize);
            // MODEL UPDATE GOES HERE
        }
    }
}

- (void) layoutSubviews { // called at every frame of scrolling
    [super layoutSubviews];
    [self recenterIfNecessary];
}

@end

Hope this helps someone.