56
votes

I've got a view and I applied a UIPanGestureRecogniser to this view:

UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAnim:)];
[sliderView addGestureRecognizer:panGesture];
[panGesture release];

I can detect and process the gesture just fine. However, I wish to initiate another method once the gesture has ended.

I know there are two methods that allow this kind of detection. touchesEnded and touchesCancelled however, I've found that touchesCancelled gets called as soon as the touch becomes a gesture i.e. I move my finger enough to warrant a gesture call and touchesEnded rarely, if ever, gets called.

I want to be able to pan left / right and then initiate another function call upon gesture ending. How do I do this?

5

5 Answers

146
votes

Pan gesture end event can be detected by checking its state with UIGestureRecognizerStateEnded.

Check with the below code .

-(void) panAnim:(UIPanGestureRecognizer*) gestureRecognizer
{
   if(gestureRecognizer.state == UIGestureRecognizerStateEnded)
   {
      //All fingers are lifted.
   }
}

From Apple documentation

A panning gesture is continuous. It begins (UIGestureRecognizerStateBegan) when the minimum number of fingers allowed (minimumNumberOfTouches) has moved enough to be considered a pan. It changes (UIGestureRecognizerStateChanged) when a finger moves while at least the minimum number of fingers are pressed down. It ends (UIGestureRecognizerStateEnded) when all fingers are lifted.

Read more about UIPanGestureRecognizer

11
votes

Pan gesture end event can be detected by checking the it's state with UIGestureRecognizerStateEnded or UIGestureRecognizerStateCancelled or UIGestureRecognizerStateFailed

Check with the below code .

   -(void) panGesture:(UIPanGestureRecognizer*) gestureRecognizer
    {
     if(gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateFailed || gestureRecognizer.state == UIGestureRecognizerStateCancelled)
             {
                //code what you want.
             }
     }
8
votes

Above answers are all correct, this is just an updated one for Swift.

Swift 3:

func panGesture(recognizer: UIPanGestureRecognizer) {
    if recognizer.state == .ended {
        // Do what you want
    }
}
2
votes

In Swift 4, use UIGestureRecognizerState.ended.

e.g.

if (gestureRecognizer.state == UIGestureRecognizerState.ended) {

        //Move label back to original position (function invoked when gesture stops)
        UIView.animate(withDuration: 0.4) {
            self.swipeLabel.center = CGPoint(x: self.view.bounds.width / 2, y: self.view.bounds.height / 2)
        }
    }

Below is all the code you need in a view controller to animate a UILabel with gesture, including when the gesture ends.

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var swipeLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()

    //Create gesture
    let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(moveLabelBasedOn(gestureRecognizer:)))

    //Assign gesture to UILabel
    swipeLabel.addGestureRecognizer(gestureRecognizer)

}

//Animate Label in Resopnse to Gesture
@objc func moveLabelBasedOn(gestureRecognizer: UIPanGestureRecognizer) {

    let changeInPosition = gestureRecognizer.translation(in: view)

    //Move label in response to gesture
    swipeLabel.center = CGPoint(x: view.bounds.width / 2 + changeInPosition.x, y: view.bounds.height / 2 + changeInPosition.y)

    //Check if gesture ended
    if (gestureRecognizer.state == UIGestureRecognizerState.ended) {

        //Move label back to original position (function invoked when gesture stops)
        UIView.animate(withDuration: 0.4) {
            self.swipeLabel.center = CGPoint(x: self.view.bounds.width / 2, y: self.view.bounds.height / 2)
        }
    }
}

}

Hope this helps.

1
votes

This would not work for a two (or more) finger pan. In this case with numberOfMinimumTouches = 2, the pan would start and you can scroll/pan around, but if you lift one finger, the pan will still continue (move to where the one finger is instead of between the two fingers), since the State.ended is only when ALL fingers are lifted. To stop based on the numberOfMinimumTouches value, a different approach needs to be implemented.