finder
finder

Reputation: 145

Drag and drop between cells in CollectionView doesn't work, iOS, PanGestureRecognizer and Swift3

I tried to create collection view, with 2 rows and 2 columns and do simple drag and drop between the cells. I will post how my controller's collectionView() and panGestureAction() look like. When I was adding the gesture recogniser to the story, I've dropped it on reusable cell.

The problem is when I try drag and drop, only last cell can throw an event, and I see console log ("began" and "ended"). If I comment line cell.contentView.addGestureRecognizer(recognizer), only first cell will throw an event.

What should I do, that all my cells are logging the message (are able to recognise drag and drop) ?

@IBOutlet weak var recognizer: UIPanGestureRecognizer!

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> 
 UICollectionViewCell {

    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReusable, for: indexPath) as? CellCollectionViewCell else {
        fatalError("The dequeued cell is not an instance of CellCollectionViewCell.")
    }

    cell.contentView.addGestureRecognizer(recognizer)

    // Configure the cell
    cell.valueLabel?.text = String(100);
    cell.layer.borderWidth = 5.0
    cell.layer.borderColor = UIColor.red.cgColor

    cells.append(cell);

    return cells[cells.count-1];
}


 @IBAction func panGestureAction(_ sender: UIPanGestureRecognizer) {
    if recognizer.state == UIGestureRecognizerState.began {
        print("began");
    }

    if recognizer.state == UIGestureRecognizerState.ended {
        print("ended");
    }
}

UPDATE:

import UIKit

class GridControllerCollectionViewController: UICollectionViewController, UIGestureRecognizerDelegate {

private let cellReusable = "CellCollectionViewCell"

fileprivate let numberOfColumns = 2
fileprivate let numberOfRows = 4
fileprivate var gesture: UILongPressGestureRecognizer?

@IBOutlet var collectionViewOutlet: UICollectionView!

fileprivate var cells = [CellCollectionViewCell]()

override func viewDidLoad() {
    super.viewDidLoad()

    gesture = UILongPressGestureRecognizer(target: self, action: #selector(panGestureAction(_:)))
    gesture?.minimumPressDuration = 0.5
    gesture?.delegate = self

    //have tried with first line, second, and with both
    collectionViewOutlet.addGestureRecognizer(gesture!)
    collectionView?.addGestureRecognizer(gesture!)

    print("gesture delegate is assigned!")
}

override func numberOfSections(in collectionView: UICollectionView) -> Int {
    return numberOfRows
}


override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return numberOfColumns
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReusable, for: indexPath) as? CellCollectionViewCell else {
        fatalError("The dequeued cell is not an instance of CellCollectionViewCell.")
    }

    // Configure the cell
    cell.valueLabel?.text = String(100);
    cell.layer.borderWidth = 5.0
    cell.layer.borderColor = UIColor.red.cgColor

    cells.append(cell);

    return cells[cells.count-1];
}

func panGestureAction(_ sender: UILongPressGestureRecognizer) {

    print("panGestureAction was reached!");

//        if gesture?.state == UIGestureRecognizerState.began {
//            print("began");
//        }
//        
//        if gesture?.state == UIGestureRecognizerState.ended {
//            print("ended");
//        }

    switch sender.state {
    case .began:
        print("began")
    case .changed:
        print("changed")
    case .ended:
        print("ended")
    default:
        collectionView?.cancelInteractiveMovement()
    }
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return true
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive press: UIPress) -> Bool {
    return true
}

override func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
    return true
}
}

Upvotes: 0

Views: 2059

Answers (1)

Jože Ws
Jože Ws

Reputation: 1814

Do not add the gesture to the cells. It must be added to your collectionView

gesture = UILongPressGestureRecognizer(target: self, action: #selector(panGestureAction(_:)))
gesture.minimumPressDuration = 0.5
gesture.delegate = self
collectionView.addGestureRecognizer(gesture)

Implement gesture delegate methods

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return true
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive press: UIPress) -> Bool {
    return true
}

IMPORTANT: Implement collection view data source method

func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    //
}

Finally, implement your pan gesture action

func panGestureAction(_ sender: UILongPressGestureRecognizer) {
    switch sender.state {
    case .began:
        guard let indexPath = collectionView.indexPathForItem(at: sender.location(in: collectionView)) else {
            return
        }
        collectionView.beginInteractiveMovementForItem(at: indexPath)        
    case .changed:
        collectionView.updateInteractiveMovementTargetPosition(sender.location(in: collectionView))
    case .ended:
        collectionView.endInteractiveMovement()
    default:
        collectionView.cancelInteractiveMovement()
    }
}

Upvotes: 2

Related Questions