1
votes

Ive now been stuck for over 2 weeks on how to drag and drop multiple items at once within a collectionView (ie reordering multiple items within a collectionView) using the new ios11 drag & drop protocols. I can't get the cells to consistently reorder correctly.

Ive tried using placeholders but that appears to be more targeted for remote drags into a collectionView with async data loads.

Ive tried following instructions given in an answer within a blog post

https://hackernoon.com/drag-it-drop-it-in-collection-table-ios-11-6bd28795b313

where the instructions given (as an answer in the list of questions at the end of the post) was as follows

Reordering multiple items in the same collection view is a bit tedious and need to be handled manually.

First of all, use UICollectionViewDropIntent as .unspecified for .move UIDropOperation in the UICollectionViewDropProposal while returning from collectionView(_:dropSessionDidUpdate:withDestinationIndexPath:), i.e.

func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal
{
    return UICollectionViewDropProposal(operation: .move, intent:  .unspecified)
}

Secondly, you need to handle the insertion and deletion of each item that you want to reorder in the collection view explicitly. Example:

let items = coordinator.items
var dIndexPath = destinationIndexPath
if dIndexPath.row >= collectionView.numberOfItems(inSection: 0)
{
  dIndexPath.row = collectionView.numberOfItems(inSection: 0) - 1
}
var sourceIndexPaths = [IndexPath]()
var destinationIndexPaths = [IndexPath]()
for item in items
{
  if let sourceIndexPath = item.sourceIndexPath
  {
    sourceIndexPaths.append(sourceIndexPath)
    destinationIndexPaths.append(dIndexPath)
    self.items2.remove(at: sourceIndexPath.row)
    self.items2.insert(item.dragItem.localObject as! String, at: dIndexPath.row)
    dIndexPath = IndexPath(row: dIndexPath.row + 1, section: 0)
  }
}
collectionView.performBatchUpdates({
  if collectionView === self.collectionView2
  {
    collectionView.deleteItems(at: sourceIndexPaths)
    collectionView.insertItems(at: destinationIndexPaths)
  }
})

This partially works but only if the destinationIndexPath is less than the sourceIndexPaths of all the drag items ie in a collectionView of 5 items, flocking items at indexPaths 3 & 4, and inserting them at indexPath 1 works and order is correct. But it doest work (some items get deleted, others get duplicated and order is incorrect) if I flock items at indexPath 0 & 1 and try to drop them at indexPath 4. This is further complicated if some of the flocked items have sourceIndexPaths less than the destinationIndexPath and others have sourceIndexPaths greater than the destinationIndexPath.

That author's sample project is at

https://github.com/pgpt10/DragAndDrop-CollectionView

Does anyone know how I can approach solving this problem.

1

1 Answers

0
votes

The problem was how to calculate correct indexPaths in the collection view as pages are being manually deleted and inserted before performBatchUpdates was called. I was able to solve the problem by inspecting the model (array of items in the collectionView) and getting the new indexPath of the current item within each loop. Was easier than manually trying to calculate how each deletion and insertion affected the system provided indexPath of subsequent drag items