Search code examples
iosswiftuicollectionviewuicollectionviewcelluipangesturerecognizer

Pan Gesture making view jump away from finger on drag


I'm having a problem when trying to drag a view using a pan gesture recognizer. The view is a collectionViewCell and the dragging code is working, except when the drag starts the view jumps up and to the left. My code is below.

In the collectionViewCell:

override func awakeFromNib() {
    super.awakeFromNib()
    let panRecognizer = UIPanGestureRecognizer(target:self, action:#selector(detectPan))
    self.gestureRecognizers = [panRecognizer]
}

var firstLocation = CGPoint(x: 0, y: 0)
    var lastLocation = CGPoint(x: 0, y: 0)
    @objc func detectPan(_ recognizer:UIPanGestureRecognizer) {
        switch recognizer.state {
        case .began:
            firstLocation = recognizer.translation(in: self.superview)
            lastLocation = recognizer.translation(in: self.superview)
        case .changed:
            let translation  = recognizer.translation(in: self.superview)
            self.center = CGPoint(x: lastLocation.x + translation.x, y: lastLocation.y + translation.y)
        default:
            UIView.animate(withDuration: 0.1) {
                self.center = self.firstLocation
            }
        }
    }

The first image is before the drag starts, the second is what happens when dragging up.

enter image description here

enter image description here


Solution

  • You're using self.center instead of using self.frame.origin.x and self.frame.origin.y then later you're setting your translation and adding it to the lastLocation.

    Effectively what's happening is that your view is calculating the position changed from the center of the view, as if you were perfectly dragging from that location and then translating + lastLocation. I'm sure just by reading that you're aware of the issue.

    The fix is simple.

    self.frame.origin.x = translation.x
    self.frame.origin.y = translation.y
    

    The difference is the starting calculation with the translation. Origin will grab the x/y position based on where the touch event begins. Whereas the .center always goes from the center.