UICollectionViewの並べ替えで起こるチラつきを解消する方法 (Prevent Blinking)

並べ替え完了後にリロードするとチラつきがなくなります。

class ReorderCollectionViewGestureRecognizer: UIPanGestureRecognizer {
    
    @IBAction private func handle(_ sender: UIGestureRecognizer) {
        guard let collectionView = sender.view as? UICollectionView else {
            fatalError("\(self) cannot handle the view")
        }
        
        switch sender.state {
        case .began:
            let location = sender.location(in: sender.view)
            if let indexPath = collectionView.indexPathForItem(at: location) {
                collectionView.beginInteractiveMovementForItem(at: indexPath)
            }
        case .changed:
            let location = sender.location(in: sender.view)
            collectionView.updateInteractiveMovementTargetPosition(location)
        case .ended:
            // 写真が着地してからリロードする
            // endInteractiveMovement()の前でセットしておく
            CATransaction.setCompletionBlock {
                // なぜか空の配列でも効果がある
                collectionView.reloadItems(at: [])
            }
            collectionView.endInteractiveMovement()
        default:
            collectionView.cancelInteractiveMovement()
        }
    }
    
    override init(target: Any?, action: Selector?) {
        super.init(target: nil, action: nil)
        addTarget(self, action: #selector(handle))
    }
    
    convenience init() {
        self.init(target: nil, action: nil)
    }
}

CATransaction.setCompletionBlockを使うと任意のアニメーションの終了を検出できます。この並べ替え専用ジェスチャーは、Storyboardでもコードでも使えます。

collectionView.addGestureRecognizer(ReorderCollectionViewGestureRecognizer())

なぜLongPressではなくPanを使ってるの?

セルの並べ替えを発動させるのはLongPressジェスチャーでも良いのですが、長押しで削除メニューを出したり、タップで何かをする場合に競合してしまいます。調整できますが、Panジェスチャーならそれらとは競合しないのでデフォルトのままで使えます。

iOS 12, 13にて確認