I'm seeing some mysterious behaviour from UICollectionView
with a custom layout (subclass of UICollectionViewLayout
) when rotating the device.
I have a simple horizontally scrolling row of cells. When rotating the device from portrait to landscape, additional cells become visible that weren't visible before, and the animation of those appearing cells is wrong (it uses the familiar ghosting effect, which I think is some kind of default animation effect for collection view layouts). Notice the cell appearing on the far left in this animation:
Some details about the custom layout setup:
shouldInvalidateLayoutForBoundsChange:
returnsYES
.- In
layoutAttributesForItemAtIndexPath:
caches the attributes in a dictionary if they haven't already been created. - In
layoutAttributesForElementsInRect:
I calculate which cells should be visible by hand, and tweak theircentre
property slightly each time, before returning their attributes.
I then have the following code to deal with the initial/final layout attributes:
- (void)prepareForAnimatedBoundsChange:(CGRect)oldBounds
{
[super prepareForAnimatedBoundsChange:oldBounds];
self.animatingBoundsChange = YES;
}
- (void)finalizeAnimatedBoundsChange
{
[super finalizeAnimatedBoundsChange];
self.animatingBoundsChange = NO;
}
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
if (self.animatingBoundsChange) {
// If the view is rotating, appearing items should animate from their current attributes (specify `nil`).
// Both of these appear to do much the same thing:
//return [self layoutAttributesForItemAtIndexPath:itemIndexPath];
return nil;
}
return [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];
}
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
if (self.animatingBoundsChange) {
// If the view is rotating, disappearing items should animate to their new attributes.
return [self layoutAttributesForItemAtIndexPath:itemIndexPath];
}
return [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];
}
It seems to me that the initial layout attributes for the newly appearing cell are somehow not right (it ends in the correct location after all). But when I log the center
property of the layout attributes returned from the initalLayout...
method, everything looks correct - all evenly spaced along the horizontal axis.
The only distinguishing feature of the cell that isn't animating correctly is that its cell isn't returned in the [collectionView visibleCells]
array when the initialLayout...
method is called. The layoutAttributesForElementsInRect:
that precedes it does correctly identify that its layout attributes are needed however.
So what's going on? Some insights into what's going on under the hood would be so helpful... UICollectionView
seems like a massive black box.