1

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...

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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 

Comments

0

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.

5 Comments

Thanks. I actually have already run and analysed that example. It does not help with my problem though, which is that cells not on screen at the time of removal are not animated. In the example, all cells are always on screen.
I see. You either need them on screen to have the method include them, you need to trick the method into thinking they're on screen, or you need to animate them yourself. I'll keep looking around and see if i can help you solve your problem.
Thanks for your help. My idea for "tricking" it was to return the soon to be deleted cells inside layoutAttributesForElementsInRect:, but I doubt that would work because the collection would probably filter them out since their frame does not intersect the passed frame. I will try it anyways. How would go about animating them yourself?
I'm looking for a good example. In the mean time, you might try batch updates? raizlabs.com/2013/10/animating_items_uicollectionview
I already do it by batch updates. The cells visible do get removed. Everything is working fine, all animations, all except the out of screen ones. By out of screen, I mean outside of the collection view "buffer", the CGRect passed to layoutAttributesForElementsInRect:

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.