6

I'm attempting to implement a collection view with an infinite scrolling behaviour. The scrolling should be circular - like in a UIPickerView. Can it be done with Apple's UICollectionView or there is no choice but to create a horizontal PickerView ?

What do you think?

rmaddy
  • 298,130
  • 40
  • 468
  • 517
Alex1987
  • 8,819
  • 14
  • 66
  • 90
  • do you mean reshow a fixed number of elements infinitely? – Eric Mar 20 '13 at 16:53
  • Even if you could, you shouldn't. `UICollectionView` is not designed for that type of behavior and would perform very poorly even if you could get around issues. – DBD Mar 20 '13 at 17:08
  • @Eric: Yes. Just like a UIPickerView – Alex1987 Mar 21 '13 at 08:48
  • 3
    @DBD, It's not true that the performance would be poor. Because of cell reuse, it doesn't matter how many apparent rows you have. The number of cells is never more than what can be seen on screen at once. – rdelmar Mar 21 '13 at 14:45
  • The example code is here: http://stackoverflow.com/a/15553973/912645 – Hai Feng Kao May 19 '13 at 00:28
  • 2
    @DBD Wrong, take a look at the calendar app – aryaxt Jun 22 '14 at 21:03

4 Answers4

3

You should watch the WWDC 2011 session video "Advanced ScrollView Techniques", they talk about infinite scrolling, and I'm pretty sure it's possible to use that with UICollectionViews. It recenters while you scroll, and places the new items after the current visible items (or before, depending on the scroll direction).

Like they say in the session, you should not use an approach that has an ending. Like stated in the session: People will definitely find the edge at one point.

Guido Hendriks
  • 5,296
  • 3
  • 25
  • 36
-1

Yes, you can do this. Return a very large number for collectionView:numberOfItemsInSection:, and in collectionView:cellForItemAtIndexPath:, you use the mod operator to always return a number for indexPath.Row that's between 0 and the last index in your data array. So if you had 20 items in your array, you would do something like this:

item.whatever.text = [self.theData objectAtIndex:indexPath.row %20];
rdelmar
  • 102,832
  • 11
  • 203
  • 218
  • What will happen if we reach the last cell ? – Alex1987 Mar 21 '13 at 08:49
  • @Alex1987, it will end, but if you set the number high enough, it would be hard to ever scroll that far. It would appear to the user that it is infinite. Picker views work this same way, they are not truly circular. – rdelmar Mar 21 '13 at 14:42
  • 1
    @rdelmar That's a wrong assumption! In fact you do have to trick the users, since it's really never a true infinite scroll. But there are better ways to implement that. Just add the items to the end/beginning if you need them, that way you don't have an ending. That seems to be "more infinite" than your solution. – Guido Hendriks Mar 22 '13 at 10:00
  • @GuidoH, I don't think it's a wrong assumption, I only said it was hard not impossible. If someone finds the end, so what. I think that this is a useful, if not ideal way to solve this problem. If the OP had the knowledge to apply what is in the WWDC 2011 video to a collection view, he wouldn't have had to ask this question in the first place -- I don't think that will be a trivial thing to do. My solution is very simple, and doesn't deserve, what I presume, was your down vote. – rdelmar Mar 22 '13 at 17:20
  • 1
    @rdelmar It's not that hard to implement what's on the WWDC session. And if you don't know how to do something properly, you just go for the wrong approach instead of learning how to do it the right way? And yes, I did down vote your answer. It was +1 when I did, so apparently I'm not the only one... – Guido Hendriks Mar 22 '13 at 17:58
  • 1
    @GuidoH, you're right about it not being that hard -- I had tried something like that in the past, but did the offset adjustment in scrollViewDidScroll, and that led to pretty jerky results, so I thought it would require quite a bit of code to get it right. Actually, it's a lot easier with a collection view than what they did in the video because the collection view already handles all the tiling stuff that they glossed over. Thanks for the heads up, I've watched a lot of this years videos, but I missed that one. – rdelmar Mar 23 '13 at 04:38
  • @rdelmar do you have a sample project (github?) when you have implemented this with UICollectionView? Your line above does help but would be great to see it all working in a sample project if possible. – Ash Dec 10 '13 at 22:48
  • @Ash, I probably have a test project, but I'm not at home right now. I'll look for it tomorrow and post it somewhere. – rdelmar Dec 11 '13 at 01:13
  • @rdelmar. Thank you, that would be great. I been trying to create an infinite Horizontal scrolling with a collection view. If it's easier you can send me the link to the test project via email or on here. – Ash Dec 13 '13 at 20:06
  • @Ash, I've uploaded a project that has infinite scrolling in both dimensions, hopefully, you can modify that to your liking. It uses the method mentioned by GuidoH in the comments. The link is http://jmp.sh/v/WObtKQbkDqyf76Wd95i7 – rdelmar Dec 13 '13 at 20:40
  • @rdelmar thanks for that much appreciated. I have up voted your answer. – Ash Dec 15 '13 at 11:28
-1

Thanks to rdelmar for a tricky solution. That idea of "large number for collectionView:numberOfItemsInSection" worked like a charm. I have tried to implement the same with UIScrollView delegate methods. But the output was jerky.

Here's some part of my code.

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

return 100;}

// CellforRow

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

// Setup cell identifier
static NSString *cellIdentifier = @"cvCell";


CVCell *cell;
        cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

        [cell.titleLabel setText:[self.dataArray objectAtIndex:(indexPath.row)%self.dataArray.count]];

return cell;

}

// DidSelect

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{


NSLog(@"Index path is %d", indexPath.row%self.dataArray.count);

}

This will give infinite scrolling effect. To enable infinite scrolling both sides, use ScrolltoIndexpath:(middle of Itemscount) in ViewWillAppear !! Hope this will help someone who are about to build an infinite scrolling UICollectionView.

Sanu S
  • 211
  • 3
  • 9
-1

Override this method to enable infinite scrolling both ways. It center content whenever it is too far from the center and user never hits the end.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint currentOffset = self.collectionView.contentOffset;
CGFloat contentWidth = self.collectionView.contentSize.width;
CGFloat centerOffsetX = (contentWidth - self.collectionView.bounds.size.width) / 2.0;
CGFloat distanceFromCenter = fabs(currentOffset.x - centerOffsetX);

if (distanceFromCenter > (contentWidth / 4.0)) {
    self.collectionView.contentOffset = CGPointMake(centerOffsetX, currentOffset.y);
}

}