I am trying to implement infinite horizontal and vertical scrolling from a UICollectionView in iOS 6. I managed to get it to work, but it is slow and choppy.
StackOverflow has similar questions, but the deepest of them is switching to Apple WDC video and implementing using a collection instead of scrolling. I based my project on this and other comments made on similar issues, but I still can't make it look smooth.
I mainly try to imitate the behavior of the HBO GO iPad application, which represents the show’s grid and allows you to scroll them in any direction, when you reach the end, it just wraps the show so that you feel like you scroll endlessly.
What I did was create a custom layout that arranges the UICollectionView cells in the grid. I then subclassed the UICollectionView, rewrote its layoutSubviews method, and created a new reecenterIfNecessary function, as shown in Eliza WDC videos. This works, and I get an infinite "scroll", but the content does not change.
So, I created a delegate that pointed to the view controller, and whenever it wraps around, I tell the delegate to move its data source, and it does, but it does not appear in the UICollectionView, so one last call [self reloadData] updates the view and everything "works." I get endless scrolling.
But since I call reloadData, the delay is noticeable and the scroll bars flicker (from the "content" that is "reloading"). This is unacceptable, and I cannot figure out how to get around this!
Any help is appreciated. I turned on the recenterIfNecessary function in case this helps.
- (void) recenterIfNecessary{ CGPoint currentOffset = [self contentOffset]; CGFloat contentHeight = [self contentSize].height; CGFloat contentWidth = [self contentSize].width; //calc center point which would leave same amount of content on both sides CGFloat centerY = (contentHeight - [self bounds].size.height) / 2.0; CGFloat centerX = (contentWidth - [self bounds].size.width) / 2.0; if (currentOffset.x == 0 && currentOffset.y == 0){ //assume this is first load. Set offset to content center. self.contentOffset = CGPointMake(centerX, centerY); return; } //distance from center is abs of where we are and where we want to be: CGFloat offsetY = centerY-currentOffset.y; CGFloat offsetX = centerX-currentOffset.x; //now we decide if we want to recenter int deltaX = 0; int deltaY = 0; if (fabs(offsetX) > CELL_WIDTH){ if (offsetX < 0){ deltaX = -ceil(offsetX / CELL_WIDTH); }else{ deltaX = -floor(offsetX / CELL_WIDTH); } offsetX += offsetX + (CELL_WIDTH * deltaX); self.contentOffset = CGPointMake(centerX, currentOffset.y); } if (fabs(offsetY) > CELL_HEIGHT){ if (offsetY < 0){ deltaY = -ceil(offsetY / CELL_HEIGHT); }else{ deltaY = -floor(offsetY / CELL_HEIGHT); } offsetY += offsetY + (CELL_HEIGHT * deltaY); self.contentOffset = CGPointMake(currentOffset.x, centerY); } if (fabs(offsetX) > CELL_WIDTH || fabs(offsetY) > CELL_HEIGHT){ //move subviews to reflect scrolling for (UIView *subview in self.subviews) { CGPoint center = subview.center; center.x += offsetX; center.y += offsetY; subview.center = center; } if ([self.infiniteDataModelDelegate conformsToProtocol:@protocol(InfiniteDataModelProtocol)]){ //moves the data model to reflect "scrolling" [self.infiniteDataModelDelegate contentDidChangeModelDeltaX:deltaX deltaY:deltaY]; } [self reloadData]; } }