Drag & Drop CollectionView Cells (Swift 5) - Xcode 11 - 2020
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
var destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath {
destinationIndexPath = indexPath
} else {
let row = collectionView.numberOfItems(inSection: 0)
destinationIndexPath = IndexPath(item: row - 1, section: 0)
}
if coordinator.proposal.operation == .move {
reorderItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
}
}
coordinator
를 통해 출발/도착 인덱스 패스 구성 가능coordinator
종류가 move
일 때 해당 함수 사용private func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) {
if
let item = coordinator.items.first,
let sourceIndexPath = item.sourceIndexPath {
collectionView.performBatchUpdates({
let temp = data[sourceIndexPath.item]
data.remove(at: sourceIndexPath.item)
data.insert(temp, at: destinationIndexPath.item)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
}) { done in
//
}
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
}
}
coordinator
등을 파라미터로 건네받아 실행import UIKit
class CollectionViewController: UIViewController {
private var data: [UIColor] = [.systemRed, .systemOrange, .systemYellow, .systemGreen, .systemBlue, .systemCyan, .systemPurple, .systemPink, .black]
private let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 1
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(DragAndDropCollectionViewCell.self, forCellWithReuseIdentifier: DragAndDropCollectionViewCell.identifier)
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.frame = view.bounds
collectionView.reloadData()
}
private func setUI() {
view.backgroundColor = .systemBackground
view.addSubview(collectionView)
collectionView.delegate = self
collectionView.dragDelegate = self
collectionView.dropDelegate = self
collectionView.dataSource = self
collectionView.dragInteractionEnabled = true
}
}
extension CollectionViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
return true
}
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
}
}
extension CollectionViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DragAndDropCollectionViewCell.identifier, for: indexPath) as? DragAndDropCollectionViewCell else { return UICollectionViewCell() }
let model = data[indexPath.row]
cell.configire(with: model)
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
}
extension CollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = (view.frame.width - 4) / 3
return CGSize(width: size, height: size)
}
}
extension CollectionViewController: UICollectionViewDropDelegate {
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
var destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath {
destinationIndexPath = indexPath
} else {
let row = collectionView.numberOfItems(inSection: 0)
destinationIndexPath = IndexPath(item: row - 1, section: 0)
}
if coordinator.proposal.operation == .move {
reorderItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
}
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
if collectionView.hasActiveDrag {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
return UICollectionViewDropProposal(operation: .forbidden)
}
private func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView) {
if
let item = coordinator.items.first,
let sourceIndexPath = item.sourceIndexPath {
collectionView.performBatchUpdates({
let temp = data[sourceIndexPath.item]
data.remove(at: sourceIndexPath.item)
data.insert(temp, at: destinationIndexPath.item)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
}) { done in
//
}
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
}
}
}
extension CollectionViewController: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
return []
}
}
import UIKit
class DragAndDropCollectionViewCell: UICollectionViewCell {
static let identifier = "DragAndDropCollectionViewCell"
override init(frame: CGRect) {
super.init(frame: frame)
setUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
}
override func prepareForReuse() {
super.prepareForReuse()
}
private func setUI() {
}
func configire(with model: UIColor) {
contentView.backgroundColor = model
}
}