Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reordering CollectionView cells iOS 11

I know that iOS 11 brings the new drag and drop functionality to collectionview but I have a completely separate issue using it. So I thought I'd try using the old way which was introduced in IOS 9 (see this link). My problem is that on iOS 11, the ending animation when your finger is removed acts weird ONLY when two cells are switched. You can see the problem in this clip.

I've been trying to figure this out for days, with no luck. It works fine on iOS 10 but not iOS 11. Any help would be appreciated.

Extra info: I'm using a collectionview with a long press gesture to initiate the reorder gesture as seen in the first link. However, the problem still occurs when using a uicollectionviewcontroller

Here's the code for the long press gesture:

func handleLongGesture(gesture: UILongPressGestureRecognizer) {

    switch(gesture.state) {

    case .began:
        guard let selectedIndexPath = self.collectionView.indexPathForItem(at: gesture.location(in: self.collectionView)) else {
            break
        }
        collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
    case .changed:
        collectionView.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!))
    case .ended:
      // this part misbehaves on ios 11 when two cells are swapped
        collectionView.performBatchUpdates({
            self.collectionView.endInteractiveMovement()
        )}
    default:
        collectionView.cancelInteractiveMovement()
    }
}
like image 727
Anthony Avatar asked Oct 30 '22 02:10

Anthony


1 Answers

To begin, you don't need to place collectionView.endInteractiveMovement() inside of a performBatchUpdates block. But nonetheless, this issue has been an annoyance for me as well. The discrepancy between iOS 10 and 11 with this endInteractiveMovement things doesn't make much sense.

For my problem, I am placing a fake snapshot cell above my collectionView, and hiding the content below as I run through gesture state changes and updateInteractiveMovementTargetPosition. Once the gesture state has .ended, I was removing the fake cell from the superview, then performing the endInteractiveMovement. But now with iOS 11, I was experiencing the same issue as @prolfe in the comments from the previous answer. I was getting this weird flash due to this unforeseen reload of the cell in question.

The solution I ended up going with was to place a delay on my fake cell removal, so that it kind of 'covers up' the flash.

My pushBackView method animates the fake cell back to the drop position, then removes the fake cell. I then enact the delay:

case .ended:

        fakeCellView?.pushBackView { [weak self] in // 'suppress' cell animation

            DispatchQueue.main.asyncAfter(deadline: .seconds(0.01), execute: {
                self?.fakeCellView?.removeFromSuperview()
            })

            self?.collectionView?.endInteractiveMovement()
        }

Hope this helps!

enter image description here

like image 147
Ryan Daulton Avatar answered Nov 15 '22 05:11

Ryan Daulton