Search code examples
iosuicollectionviewuikituicollectionviewcelluicollectionviewlayout

UI-Issues while reordering UICollectionView with full-width and dynamic height cells


I have a CollectionView with cells that have full-width and a dynamic (auto-layout-calculated) height.

I do so by setting an estimated height:

flowLayout.estimatedItemSize = CGSize(width: 200, height: 10)

Then returning the full width and a arbitrary height in the delegate method.

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: collectionView.bounds.width, height: 10)
}

Then in the cell I do the following:

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    setNeedsLayout()
    layoutIfNeeded()
    let size = self.systemLayoutSizeFitting(layoutAttributes.size)

    var newFrame = layoutAttributes.frame
    // note: don't change the width
    newFrame.size.height = ceil(size.height)
    layoutAttributes.frame = newFrame

    return layoutAttributes
}

Everything works as expected... Cells size like they should! Great!

Now I'd like to add reordering... I add a GestureRecognizer and make it rearrange my cells..

@objc func handleLongPress(gestureRecognizer: UILongPressGestureRecognizer) {

    guard let view = gestureRecognizer.view else { return }
    let location = gestureRecognizer.location(in: view)

    switch gestureRecognizer.state {
    case .began:
        guard let selectedIndexPath = collectionView.indexPathForItem(at: location) else { break }
        collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
    case .changed:
        collectionView.updateInteractiveMovementTargetPosition(location)
    case .ended:
        collectionView.endInteractiveMovement()
    default:
        collectionView.cancelInteractiveMovement()
    }
}

This also basically works... but during reordering, my cells with animate strangely... The cells sometimes reduce their size to my size of 10 but won't let the cell measure itself. After letting go of the drag, it then works again...

I noticed that when I cache the heights of my CollectionViewCells, it's a bit better, but for all cells that I haven't seen before, it will again be a 10 points high cell.

What am I missing in order to have the cells size be correct during reordering?

Sample

I also have a sample project with this problem that can be found here: https://www.dropbox.com/s/ya6zald4wa6kg10/CollectionViewTester.zip?dl=0


Solution

  • The problem is, that when reordering auto-sized cell, the cells size changes to the estimatedItemSize.

    There is an open radar reported here.