UICollectionView interactive layout transition using iOS 7 APIs

Tim Arnold picture Tim Arnold · Sep 25, 2013 · Viewed 18.3k times · Source

I'm trying to get a handle on new iOS 7 APIs that allow for interactive, animated view controller transitions, including transitions between UICollectionViewLayouts.

I've taken and modified sample code from WWDC 2013, "iOS-CollectionViewTransition", which can be found here: https://github.com/timarnold/UICollectionView-Transition-Demo

The original demo, which was not in a working state when I found it, can be accessed with an Apple Developer account, here: https://developer.apple.com/downloads/index.action?name=WWDC%202013

My version of the app presents a collection view with two layouts, both UICollectionViewFlowLayout layouts with different properties.

Tapping on a cell in the first layout properly animates to the second, including, crucially, the tapped-on-item being scrolled to in the new layout. At first I was confused about how the new collection view knows to set its content offset so that the appropriate cell is visible, but I learned it does this based on the selected property of the presenting collection view.

Pinching on an item in the first layout should animate, using UICollectionViewTransitionLayout, UIViewControllerAnimatedTransitioning, and UIViewControllerInteractiveTransitioning, to the new layout as well. This works, but the pinched-at cell is not scrolled to in the new layout or the transition layout.

I've tried setting the selected property on the pinched-on cell at various locations (to try to mimic the behavior described when tapping on an item to push the new view controller), to no avail.

Any ideas about how to solve this problem?

Answer

Timothy Moose picture Timothy Moose · Oct 8, 2013

You can manipulate the contentOffset yourself during the transition, which actually gives you finer-grained control than UICollectionView's built-in animation.

For example, you can define your transition layout like this to interpolate between the "to" and "from" offsets. You just need to calculate the "to" offset yourself based on how you want things to end up:

@interface MyTransitionLayout : UICollectionViewTransitionLayout
@property (nonatomic) CGPoint fromContentOffset;
@property (nonatomic) CGPoint toContentOffset;
@end

#import "MyTransitionLayout.h"
@implementation MyTransitionLayout

- (void) setTransitionProgress:(CGFloat)transitionProgress
{
    super.transitionProgress = transitionProgress;
    CGFloat f = 1 - transitionProgress;
    CGFloat t = transitionProgress;
    CGPoint offset = CGPointMake(f * self.fromContentOffset.x + t * self.toContentOffset.x, f * self.fromContentOffset.y + t * self.toContentOffset.y);
    self.collectionView.contentOffset = offset;
}

@end

One thing to note is that the contentOffset will be reset to the "from" value when the transition completes, but you can negate that by setting it back to the "to" offset in the completion block of startInteractiveTransitionToCollectionViewLayout

CGPoint toContentOffset = ...;
[self.collectionViewController.collectionView startInteractiveTransitionToCollectionViewLayout:layout completion:^(BOOL completed, BOOL finish) {
    if (finish) {
        self.collectionView.contentOffset = toContentOffset;
    }
}];

UPDATE

I posted an implementation of this and a working example in a new GitHub library TLLayoutTransitioning. The example is non-interactive, intended to demonstrate improved animation over setCollectionViewLayout:animated:completion, but it utilizes the interactive transitioning APIs combined with the technique described above. Take a look at the TLTransitionLayout class and try running the "Resize" example in the Examples workspace.

Perhaps TLTransitionLayout can accomplish what you need.

UPDATE 2

I added an interactive example to the TLLayoutTransitioning library. Try running the "Pinch" example in the Examples workspace. This one pinches the visible cells as a group. I'm working on another example that pinches an individual cell such that the cell follows your fingers during the transition while the other cells follow the default linear path.

UPDATE 3

I've recently added more content offset placement options: Minimal, Center, Top, Left, Bottom and Right. And transitionToCollectionViewLayout: now supports 30+ easing functions courtesy of Warren Moore's AHEasing library.