UICollectionViewの並べ替えで起こるチラつきを解消する (Prevent Blinking)
2021/01/12
並べ替え完了後にリロードするとチラつきがなくなります。
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にて確認