Stefan Fachmann Stefan Fachmann - 4 months ago 47
Swift Question

UIGestureRecognizerState.Cancelled vs UIGestureRecognizerState.Failed

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.

Answer

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.

If the gesture recognizer transitioned from .Possible to .Began, than to .Failed or .Cancelled, the gesture recognition will simply fail and nothing will happen.

But if the gesture recognizer transition from .Possible directly to .Failed or .Cancelled, the next gesture recognizer in the queue(attached to a view) will have the oportunity 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)
        if touches.count == 1 {
            //state = .Failed
            print("state: \(state.rawValue)")
        }
        //state = .Began
        print("CustomGestureRecognizer.touchesBegan")
    }

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

        if state == .Failed {
            return
        }

        state = .Changed

        if touches.count == 1 {
            state = .Cancelled //.Failed
            print("state: \(state.rawValue)")
        }

        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 lines 12 and 26 to see the differences.