Fixing CircleLayout


CircleLayout is an Apple sample from WWDC 2012 (Session 219) that demonstrates a custom collection view layout and also custom animations when inserting and removing items from the collection.  The trouble is that in the time since this sample was published, the UICollectionView API has changed somewhat and the sample no longer works.

The project still compiles and runs (once you import the Quartz header in Cell.m), displays items in a circular layout, and you can insert or remove cells by tapping either off or on a cell, and the remaining cells animate to their new positions.  However, in the original sample, cells being removed shrunk and faded out to the center while cells being inserted moved out from the center while fading in, but that no longer happens.

The initial problem is that the 2 methods for providing the custom attributes for the inserted/removed cells has been renamed.  If you fix that, then you start getting custom animations, but something really bizarre happens: when you insert or remove a cell, all the cells shrink away to the center (before reappearing in their correct places).  What’s going on?

The answer is that initialLayoutAttributesForAppearingItemAtIndexPath: and finalLayoutAttributesForDisappearingItemAtIndexPath: are not just called for the inserted and removed cell(s), respectively.  They’re called for all visible cells; i.e. those that need to move as well as the one(s) being inserted or removed.  Not only that but initialLayoutAttributesForAppearingItemAtIndexPath: even gets called when removing an item and finalLayoutAttributesForDisappearingItemAtIndexPath: also gets called when inserting an item!

The Solution

prepareForCollectionViewUpdates: gets called before any insert/delete animations occur.  We can use that to record the indexPaths of those items being inserted or removed (don’t forget to call super).  Then in initialLayoutAttributesForAppearingItemAtIndexPath: we only need to modify the attributes for indexPaths that match the insert operations, and in finalLayoutAttributesForDisappearingItemAtIndexPath: we only need to modify the attributes for indexPaths that match the delete operations.  Again, don’t forget to call super because especially for initialLayoutAttributesForAppearingItemAtIndexPath: this returns non-nil values for the items being moved, and the remaining cells won’t animate their moves to their new positions without it.

I posted my corrected version of the CircleLayout project to GitHub, and if you’re interested you can check out the commit changes to CircleLayout.m to see what I changed to reinstate the custom animations.

UICollectionView is one of my favorite new bits of API in iOS 6.  I can’t wait to see how it develops and matures, and am eagerly awaiting my first iOS 6-only project so that I can put a collection view into production code.