1

What is the difference between the .Cancelled and .Failed states?

How does setting gesture recognizer's state to .Cancelled or .Failed affect the gesture recognizer itself?

When does a gesture recognizer's state become .Cancelled and .Failed?

At which point is a gesture recognizer marked as 'recognized'? After transition to .Began?

When yes, can the gesture's state set to .Began in touchesMoved also?

For example at which stage is a pinching gesture recognized by UIPinchGestureRecognizer? I guess only in touchesMoved because pinching is a continuos gesture.

Wyetro
  • 8,439
  • 9
  • 46
  • 64
Stefan Fachmann
  • 555
  • 1
  • 5
  • 18

2 Answers2

4

Actually there is no difference between the .Cancelled and .Failed states. Both leading to gesture recognizer failing to handle the gesture. I guess it is just a naming convention.

Though, the difference is also how both states affect the gesture handling.

It depends of what the previous state of the gesture recognizer was.

  1. If the gesture recognizer transitioned from .Possible to .Began in touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) (UITouchPhase.Began phase of the touch), than in the same method to .Failed or .Cancelled, the next gesture recognizer in the queue(attached to a view) will have the opportunity to handle the gesture. No action message will be send.
  2. But if the gesture recognizer transitioned from .Possible to .Began in touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) (UITouchPhase.Began phase of the touch), than in the touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent) method to .Failed or .Cancelled the gesture recognition will simply fail and nothing will happen. But the action message will be send anyway.
  3. If you comment out the code on line 8, then the gesture recognition will fail and the next gesture recognizer attached to the view will have the opportunity to handle the gesture.

So here the view controller:

class ViewController: UIViewController {

    func panHandler(sender: UIPanGestureRecognizer) {
         print("panHandler")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let customRecognizer = CustomGestureRecognizer(target: self, action: #selector(ViewController.customHandler(_:)))
        view.addGestureRecognizer(customRecognizer)

        let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(ViewController.panHandler(_:)))
        view.addGestureRecognizer(panRecognizer)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func customHandler(c: CustomGestureRecognizer) {
        print("customHandler")
    }
}

and here a custom gesture recognizer:

import UIKit
import UIKit.UIGestureRecognizerSubclass

class CustomGestureRecognizer: UIGestureRecognizer {

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) {
        super.touchesBegan(touches, withEvent: event)
        state = .Began
        if touches.count == 1 {
            //state = .Failed
        }
        print("CustomGestureRecognizer.touchesBegan")
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent) {
        super.touchesMoved(touches, withEvent: event)

        if state == .Failed {
            return
        }

        if touches.count == 1 {
            state = .Failed //.Cancelled
        }

        state = .Changed
        print("CustomGestureRecognizer.touchesMoved")
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent) {
        super.touchesEnded(touches, withEvent: event)
        state = .Ended
        print("CustomGestureRecognizer.touchesEnded")
    }
}

Just comment/uncomment the code on lines 8, 10 and 23 to see the differences.

Stefan Fachmann
  • 555
  • 1
  • 5
  • 18
3

Here are the differences between

.Cancelled

The gesture recognizer has received touches resulting in the cancellation of a continuous gesture. It sends its action message (or messages) at the next cycle of the run loop and resets its state to UIGestureRecognizerStatePossible.

and

.Failed

The gesture recognizer has received a multi-touch sequence that it cannot recognize as its gesture. No action message is sent and the gesture recognizer is reset to UIGestureRecognizerStatePossible.

To paraphrase, .Cancelled is called when a continuous gesture is interrupted. .Failed is called when a gesture is not recognized as a certain type of gesture.

Graham
  • 7,431
  • 18
  • 59
  • 84
Wyetro
  • 8,439
  • 9
  • 46
  • 64