20

I have a full-screen UICollectionView in my app. It scrolls horizontally and each cell fills the collection view's bounds. The collection view is managed by a UIViewController.

Given that each "page" is reasonably complex, it makes sense for each page itself to be managed by an associated UIViewController. iOS 5 has support for view controller containment, so that the child controllers should receive the appropriate lifecycle methods (e.g. viewWillAppear:, etc) when views are attached and detached. How nicely would this play with view recycling?

Scrolling from page "1", to "2", a new view would be created (as both could be onscreen at the same time during the touch-down). Moving from page "2" to "3", the UICollectionView could successfully dequeue the view for page "1", but what happens now? Would I forcefully insert the view into view controller three like so?

id cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ident" forIndexPath:indexPath];
UIViewController *child_controller = [self controllerAtIndexPath:indexPath];
[child_controller setView:cell];
// ... and so on

This feels wrong. However, I can't think of a correct way to reuse views correctly in this instance. Am I taking the wrong approach entirely?

Aidan Steele
  • 10,999
  • 6
  • 38
  • 59
  • 8
    If each cell fills the collection view's bounds, why not just use a `UIPageViewController` with its `transitionStyle` set to `UIPageViewControllerTransitionStyleScroll`? It's designed to host one child view controller per page. – rob mayoff Jun 27 '13 at 00:22

3 Answers3

8

I don't think that UICollectionView is the best choose for your task.
Like rob mayoff said: you can use UIPageViewController.
Another option can be using UIScrollView with 3 subviews (previous, current, next). And you will be able to easy manage it's position and scroll view offset to achieve effect that you want.
This is described in WWDC 2011 'Advanced Scrollview Techniques'. You can grab source code from there.

Community
  • 1
  • 1
Sergey Kuryanov
  • 6,114
  • 30
  • 52
  • I completely agree with Sergey: this task is what UIPageViewController created for. – MrTJ Jul 03 '13 at 07:32
  • @Sergey Kuryanov ,I am in same situation but Facing issues of memory in UIPageViewController ,any help you can provide to solve memory issues .I am using arc – DAMM108 Apr 03 '15 at 07:46
  • Maybe you are trying to save too many VC at the same time. It's hard to detect problem without actual code. – Sergey Kuryanov Apr 05 '15 at 19:31
7

I've done the same thing, but with two view controllers visible at once, and reorderable, so a collection view was the right choice.

It turned out that removing the previous view controller's view and adding a new one caused quite a performance hit on scrolling, with removing the view being the slowest method.

Reuse of cells only makes sense if the new use of the cell is similar, but different - e.g. you're changing the text of a label or putting a different image in an image view. If you're ripping out and replacing the whole view hierarchy, you're not really reusing the cell.

What I ended up doing was using new cells for each view controller that could be contained. In my case there was a limit on the number of cells meaning that there wasn't really a problem with memory consumption having that many view controllers in play at once.

So, in a nutshell - don't reuse cells. It's more expensive than keeping the old ones around. Scrolling down a hundred row table is different to scrolling across a few full screen views. But, given the fact yours are full screen, a scroll view might be a better option.

jrturton
  • 118,105
  • 32
  • 252
  • 268
  • I'm doing the exact same thing right now (the edges of other vc's visible, a la the app store search results). Any other problems you ran into or pointers? – Bob Spryn Nov 14 '13 at 20:39
  • 1
    The only thing I found useful was to have all the child view controllers adopt a protocol which allowed the collection view's controller to tell them when they were moving on and off screen - and in there, you'd do the viewDidAppear / disappear stuff, which otherwise wouldn't get called, because the views only appeared once. – jrturton Nov 15 '13 at 09:01
  • Did you end up using paging to force them to the next item? Trying to decide if `.pagingEnabled` is best of `targetContentOffsetForProposedContentOffset`. – Bob Spryn Nov 16 '13 at 00:54
  • 2
    The customer wanted to "fling" the scrolling so I couldn't do paging, had to implement my own snapping. They wanted it to feel like paging, but with the ability to scroll past multiple items.if you can, use paging, it's much simpler. – jrturton Nov 16 '13 at 09:28
  • Looks like you can't really use paging when you have multiple visible, because you don't want it to page the entire frame. And you can't shrink the frame and use `clipsToBounds=NO` because Collection view gets rid of the cells that aren't within the frame. – Bob Spryn Nov 16 '13 at 18:05
  • It seems it's forcing me to use the deque method to make new collection view cells so they have a reuse identifier. How did you get around that? – Bob Spryn Nov 20 '13 at 01:14
  • I registered multiple reuse identifiers with the same cell class, e.g. cell0, cell1, and created the reuse identifier based on the index path. – jrturton Nov 20 '13 at 07:28
  • Looks like you HAVE to use a nib to create your own cell that you don't want to dequeue. http://stackoverflow.com/questions/13281631/setting-reuseidentifier-on-a-uicollectionviewcell – Bob Spryn Nov 20 '13 at 22:51
6

It's probably better to use UIView subclasses (or UICollectionViewCell subclasses) instead of encapsulated UIViewControllers. The encapsulated UIViewControllers have to have knowledge of their parent view controller, which could cause problems with code maintainability.

Complexity doesn't automatically mean you should look at adopting UIViewController. UIViews can be quite complex as well. The role of a UIViewController is really to provide additional encapsulation and lifecycle that it doesn't sound like you need here.

As other's have said, UIPageViewController seems like a good alternative too, but I don't know the specifics of your situation.

Colin Cornaby
  • 741
  • 4
  • 14