I'm working on a custom UICollectionView + Layout where the cells overlap on top of each other. On top of this, I'm implementing custom animations for the addition and removal of items.
Everything's working fine, except the zIndex
property of the attributes seem to be ignored during insertion/deletion of items.
Here's my implementation for custom insertion/deletion animations. My guess is the problem is somewhere in these methods.
override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = layoutAttributesForItemAtIndexPath(itemIndexPath)
for updateItem in updateItems {
switch updateItem.updateAction {
case .Insert:
if updateItem.indexPathAfterUpdate == itemIndexPath {
let translation = collectionView!.bounds.height
attributes?.transform = CGAffineTransformMakeTranslation(0, translation)
break
}
default:
break
}
}
return attributes
}
override func finalLayoutAttributesForDisappearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
for updateItem in updateItems {
switch updateItem.updateAction {
case .Delete:
if updateItem.indexPathBeforeUpdate == itemIndexPath {
let attributes = layoutAttributesForItemAtIndexPath(itemIndexPath)
let translation = collectionView!.bounds.height
attributes?.transform = CGAffineTransformMakeTranslation(0, translation)
return attributes
}
case .Move:
if updateItem.indexPathBeforeUpdate == itemIndexPath {
return layoutAttributesForItemAtIndexPath(updateItem.indexPathAfterUpdate!)
}
default:
break
}
}
let finalIndex = finalIndexForIndexPath(itemIndexPath)
let shiftedIndexPath = NSIndexPath(forItem: finalIndex, inSection: itemIndexPath.section)
return layoutAttributesForItemAtIndexPath(shiftedIndexPath)
}
private func finalIndexForIndexPath(indexPath: NSIndexPath) -> Int {
var newIndex = indexPath.item
for updateItem in updateItems {
switch updateItem.updateAction {
case .Insert:
if updateItem.indexPathAfterUpdate!.item <= newIndex {
newIndex += 1
}
case .Delete:
if updateItem.indexPathBeforeUpdate!.item < newIndex {
newIndex -= 1
}
case .Move:
if updateItem.indexPathBeforeUpdate!.item < newIndex {
newIndex -= 1
}
if updateItem.indexPathAfterUpdate!.item <= newIndex {
newIndex += 1
}
default:
break
}
}
return newIndex
}
Things I've tried:
- Setting the
zIndex
in theinitialLayoutAttributes...
method to the value it will end up being. - Making the collection view manually reorder the cells after the animation (which is pretty hacky, and I'd like to avoid this, since it can cause some weird behaviour sometimes).
- Calling
super.initialLayoutAttributes...
etc and modifying the attributes returned from that. The issue with that is it does not handle the other cells shifting when a new one is inserted; instead the cells fade in and out.
A small reproducer of the project can be found on my GitHub. Feel free to clone it and play around with it.
As I suspected, it seems the collection view is not properly applying the layout attributes during the animation. Luckily,
UICollectionViewCell
provides a method for you to implement custom layout attributes:Adding the above code results in the inserted cell appearing at the correct zIndex.
I'll log a radar and comment with the link.