Question

I am implementing a custom UICollectionViewLayout, to create a grid containing rows.

When a row is selected (ie. when a cell from a row is selected), I insert more rows underneath the selected row. When I tap that row again, I remove these added rows with a "collapse effect" (ie. all the removed rows move up and end their animation "behind" the deselected row).

It all works well, except if the number of subrows is big, and some of the rows are not visible on screen at the time they are removed, they are not animated and a big gap shows up between the last visible row removed and the first non-removed row.

I noticed that finalLayoutAttributesForDisappearingItemAtIndexPath is not called for the disappearing items not current on screen.

Is there any way to force the Collection View to display the disappearing cells just for the animation?

EDIT =============================================================================

I recreated the problem by slightly tweaking the Apple CircleLayout example. Code can be downloaded here: https://github.com/fabienwarniez/CircleLayout

If you run the project, then click 4 times on the background (it will add 12 cells to the view), then enable the slow animation mode by typing Cmd+T, then click one of the cells (which removes 8 cells starting from the second one), you will see that the cells that were not on screen don't animate, they just appear, the ones closer to the edge of the screen do animate.

If you look at the log you can see which methods get called. When removing the 8 final cells, some of the methods get called twice! For example, layoutAttributesForItemAtIndexPath: on index path 0-5 gets called twice in the same sequence... initialLayoutAttributesForAppearingItemAtIndexPath: also gets called twice on 0-5...

I am tempted to file a bug to Apple, unless someone can point out what I am missing...

Was it helpful?

Solution

After spending so much time on this, and not being able to find any information, I submitted a support request to Apple who confirmed that it is a bug and there is no workaround for it at the moment.

OTHER TIPS

This bug can be fixed in this way:

// 1. Define inset: 
let inset = [Container height]

// 2. Set top inset: 
collectionView.contentInset.top = inset

// 3. Set bottom inset: 
collectionView.contentInset.bottom = inset

// 4. Set top constraint: 
collectionView.topAnchor.constraint(equalTo: [Container topAnchor], constant: -inset).isActive = true

// 5. Set bottom constraint: 
collectionView.bottomAnchor.constraint(equalTo: [Container bottomAnchor], constant: inset).isActive = true

This link: http://markpospesel.wordpress.com/2012/10/25/fixing-circlelayout/ may be helpful to you. Get a handle on the rows in prepareForCollectionViewUpdates:

Here's the actual text from the blog:

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top