I am building an app which enables user to drag a UIView onto another. Currently I have the implementation as a UIScrollView but that does not give me the best experience as to achieve an experience like Apple's drag and drop requires handling of many cases ( including edge cases).
I am curious if this can be done using a UICollectionView. I am looking to drag cells onto another cells after which the cells contents merge and the source cell is removed.
Any idea/ suggestion would be appreciated. I am not sure if adding what I have is neccessary but if needed I can certainly add the code which I have.
Yes it's possible with UICollectionView.
Assign below delegates to UICollectionView:
UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDragDelegate, UICollectionViewDropDelegate
Write below DataSource methods:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return YourDataSource.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PDFViewCollectionViewCell.reuseIdentifier, for: indexPath) as! PDFViewCollectionViewCell
return cell
}
then write delegate methods for dragging:
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let item = "\(indexPath.item)"
let itemProvider = NSItemProvider(object: NSString(string: "\(indexPath.item)"))
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
print("DRAG ITEM IN BEGIN: \(item)")
return [dragItem]
}
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {
let destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath {
destinationIndexPath = indexPath
} else {
let section = collectionView.numberOfSections - 1
let row = collectionView.numberOfItems(inSection: section)
destinationIndexPath = IndexPath(row: row, section: section)
}
if let item = coordinator.items.first,
let sourceIndexPath = item.sourceIndexPath {
collectionView.performBatchUpdates {
let objNeedToInsert = YourDataSource[Int(item.dragItem.localObject as! String)!]
self.YourDataSource.remove(at: sourceIndexPath.item)
self.YourDataSource.insert(objNeedToInsert, at: destinationIndexPath.item)
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [destinationIndexPath])
}
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
}
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
if collectionView.hasActiveDrag {
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
return UICollectionViewDropProposal(operation: .forbidden)
}
Best of Luck... Happy Coding :)