UICollectionView drag finger over cells to select them

Swift 3: Swipe to select with auto scrolling and working scroll.

var selectMode = false
var lastSelectedCell = IndexPath()

func setupCollectionView() {
    collectionView.canCancelContentTouches = false
    collectionView.allowsMultipleSelection = true
    let longpressGesture = UILongPressGestureRecognizer(target: self, action: #selector(didLongpress))
    longpressGesture.minimumPressDuration = 0.15
    longpressGesture.delaysTouchesBegan = true
    longpressGesture.delegate = self
    collectionView.addGestureRecognizer(longpressGesture)

    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didPan(toSelectCells:)))
    panGesture.delegate = self
    collectionView.addGestureRecognizer(panGesture)
}

func selectCell(_ indexPath: IndexPath, selected: Bool) {
    if let cell = collectionView.cellForItem(at: indexPath) {
        if cell.isSelected {
            collectionView.deselectItem(at: indexPath, animated: true)
            collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.centeredVertically, animated: true)
        } else {
            collectionView.selectItem(at: indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.centeredVertically)
        }
        if let numberOfSelections = collectionView.indexPathsForSelectedItems?.count {
            title = "\(numberOfSelections) items selected"
        }
    }
}

func didPan(toSelectCells panGesture: UIPanGestureRecognizer) {
    if !selectMode {
        collectionView?.isScrollEnabled = true
        return
    } else {
        if panGesture.state == .began {
            collectionView?.isUserInteractionEnabled = false
            collectionView?.isScrollEnabled = false
        }
        else if panGesture.state == .changed {
            let location: CGPoint = panGesture.location(in: collectionView)
            if let indexPath: IndexPath = collectionView?.indexPathForItem(at: location) {
                if indexPath != lastSelectedCell {
                    self.selectCell(indexPath, selected: true)
                    lastSelectedCell = indexPath
                }
            }
        } else if panGesture.state == .ended {
            collectionView?.isScrollEnabled = true
            collectionView?.isUserInteractionEnabled = true
            swipeSelect = false
        }
    }
}

func didLongpress() {
    swipeSelect = true
}

You could use UIPanGestureRecognizer. And based on the location of the pan events, tracking what cells are passed through. When the gesture ends, you would have an array of selected cells.

Make sure that cancelsTouchesInView is set to NO. You'll need to set the delegate with gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: and gestureRecognizerShouldBegin implemented to make sure the CollectionView can still scroll


In iOS 13 and later, you can simply use the built-in multiselection gestures. See Selecting Multiple Items with a Two-Finger Pan Gesture. Make sure you set collectionView.allowsMultipleSelectionDuringEditing to true.