UICollectionViewで並び順の入れ替えをしたい場合、Drag and Dropの処理を使用すると、簡単に良い感じに実装できます。(iOS11以上)
初期設定
ViewDidLoad内などで、Drag and Dropを使えるように初期設定をします。
collectionViewのdragDelegateとdropDelegateを追加し、dragInteractionEnabledをtrueに設定します。
collectionView.dropDelegate = self
collectionView.dragDelegate = self
collectionView.dragInteractionEnabled
UICollectionViewDragDelegate
UICollectionViewDragDelegateのitemsForBeginningを実装します。
extension ViewController: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let itemIdentifier = indexPath.item.description
let itemProvider = NSItemProvider(object: itemIdentifier as NSItemProviderWriting)
let dragItem = UIDragItem(itemProvider: itemProvider)
return [dragItem]
}
}
UICollectionViewDropDelegate
UICollectionViewDropDelegateのdropSessionDidUpdate、performDropWithを実装します。
extension MemoViewController: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
}
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
if coordinator.proposal.operation == .move {
guard let item = coordinator.items.first,
let destinationIndexPath = coordinator.destinationIndexPath,
let sourceIndexPath = item.sourceIndexPath else {
return
}
collectionView.performBatchUpdates({
// データソースの更新
let n = dataList.remove(at: sourceIndexPath.item)
dataList.insert(n, at: destinationIndexPath.item)
//セルの移動
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
})
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
}
}