Home How to Drag & Reorder CollectionView Cells
Post
Cancel

How to Drag & Reorder CollectionView Cells

Reordering Collection View Cells is a feature that was introduced in iOS 9. It is a surprisingly easy interaction to build, both in collectionviews and tableviews. By leveraging the UILongPressGestureRecognizer class we can easily implement a drag and reorder interaction of collectionview cells. It’s simply matter of updating the collectionview’s data model to match the re-order.

Overview

There are two things that needs to be done for us to implement the drag to reorder interaction:

  1. Setup long press gesture recognizer to handle interactive drag movement.

  2. Override collectionview’s two delegate methods that’s responsible for reordering cells.

Getting Started

Initialize and add a long press gesture recognizer to your collectionview:

1
2
3
let longGestureGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture))
collectionView.addGestureRecognizer(longGestureGesture)

Don’t forget to create a target selector for your gesture recognizer:

1
2
3
4
5
6
7
8
9
10
11
12
13
 @objc fileprivate func handleLongPressGesture(gesture: UILongPressGestureRecognizer) {
        switch gesture.state {
        case .began:
            guard let targetIndexPath = collectionView.indexPathForItem(at: gesture.location(in: collectionView)) else {return}
            collectionView.beginInteractiveMovementForItem(at: targetIndexPath)
        case .changed:
            collectionView.updateInteractiveMovementTargetPosition(gesture.location(in: collectionView))
        case .ended:
            collectionView.endInteractiveMovement()
         default:
            collectionView.cancelInteractiveMovement()
        }
    }

There is only 3 gesture states we are concerned with: the .began, .changed, and .ended states.

The .began case logic:
Once the user long press interaction begins, we want to locate the cell they are long pressing, then we want to start the movement of that cell, so that when the user drags the cell, the cell will move accordingly with the finger. To accomplish this we leverage the collectionview’s indexPathForItem method to grab the cell’s indexPath and then we signal to the collectionview to begin interactive movement through it’s beginInteractiveMovementForItem method.

Note: The targetIndexPath constant is unwrapped because the indexPathForItem method is not guaranteed to return an indexPath. Since the user might be long pressing between cells or the collectionview’s padded area, might not necessarily have a location, hence the unwrapping.

The .changed, .ended and default cases are pretty straightforward and self-explanatory.

Updating CollectionView’s Data Model

With the long press gesture recognizer setup to handle collectionview interaction, we have to update the data models

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Responsible for collectionView Re-order
//1
    override func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
        return true
    }
   
    //2
    override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath,
                                 to destinationIndexPath: IndexPath) {
        
        // first grab and remove item at sourceIndex
        let photo = photosArray.remove(at: sourceIndexPath.item)
        photosArray.insert(item, at: destinationIndexPath.item)

        
    }

  1. This method enables us to specify which cells we want to allow the user to move. This can be pretty useful when dragging and reordering items between multiple sections. It can be used to enabled or disable reordering interaction for a specific cell or even an entire collectionview section. Here we return true since we want all our cells to be movable in this scenario.

  2. This method is responsible for updating our data model. Making sure the cells order matches the data model’s. When this method is not implemented the cells will essentially return to their old positions when the collectionview is scrolled. When a cell is moved to a new position, the original index position in the array is removed and the new index position Is inserted into the array.

Note: The sourceIndexPath is the Initial index path where the long press gesture begins. While the destinationIndexPath is the final index path the user drags the cell.

Done 🙌✊🥳🎉👏

That’s all. Build and Run the project, long-press a cell and reorder it.

Resources

Download the source code. The project contains a collectionview that has two sections, each cell cell contains a letter from the alphabet or an emoji. Drag to reorder the cells to make words.

This post is licensed under CC BY 4.0 by the author.