UIView touchesBegan won't fire when UILongPressGestureRecognizer minimumPressDuration zero

326 Views Asked by At

MyView's and ViewController's touchesBegan won't fire if gestures minimumPressDuration is set to ".zero" but whenever I set it to ".leastNormalMagnitude" it does. Here is the code:

class ViewController: UIViewController {

    let mySuperView: UIView = {
        let v = UIView()
        v.backgroundColor = .blue
        v.frame = CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: 500, height: 500))
        return v
    }()
    
    let mySubview: MyView = {
        let v = MyView()
        v.backgroundColor = .orange
        v.frame = CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: 250, height: 250))
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.addSubview(mySuperView)
        
        mySuperView.addSubview(mySubview)
        
        let gesture = UILongPressGestureRecognizer(target: self, action: #selector(tapped(_:)))        

        gesture.minimumPressDuration = .zero // when it's set to ".leastNormalMagnitude",
                                             // MyView's and VC's touchesBegan fires.

        mySuperView.addGestureRecognizer(gesture)
    }

    @objc func tapped(_ gesture: UITapGestureRecognizer) {
        print("long pressed.")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("touchesBegan in vc") // -> Won't get called.
        super.touchesBegan(touches, with: event)
    }
    
}

class MyView: UIView {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("touchesBegan in MyViewClass") // -> Won't get called.
        super.touchesBegan(touches, with: event)
    }
}

I guess I can use it with ".leastNormalMagnitude", still I want to know why is this happening?

1

There are 1 best solutions below

2
Eugene Dudnyk On BEST ANSWER

Despite the misuse of UILongPressGestureRecognizer for a scenario where UITapGestureRecognizer has to be used instead, I will focus on answering the "why" part.

When you set gesture.minimumPressDuration = .zero, the long-press gesture gets instantly recognized.

By default, gesture recognizers tend to delay touches in view, and cancel them if they recognize the gesture.

In order to override this behavior, set

gesture.cancelsTouchesInView = false // to recieve touchesBegan callback even if gesture is recognized
gesture.delaysTouchesBegan = false // to not delay touchesBegan callback
gesture.delaysTouchesEnded = false // to not delay touchesEnded callback