iosobjective-cuigesturerecognizergestureuipangesturerecognizer

why the "shouldReceiveTouch" returns "NO", the "PanGesture" still works?


Such as title, I have a superView A and a childView B. The A has a panGestureRecognizer. When I swipe the B, it will trigger the panGestureRecognizer of A. So I return No in the shouldReceiveTouch of A, But the panGestureRecognizer still works whick makes me confused.


Solution

  • I used the following and it seems to work as expected:

    class ViewController: UIViewController {
    
        private lazy var topView: UIView = {
            let view = UIView(frame: .init(x: 100.0, y: 200.0, width: 200.0, height: 200.0))
            view.backgroundColor = UIColor.green
            return view
        }()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let bottomView = self.view
            bottomView?.backgroundColor = UIColor.red
            bottomView?.addSubview(topView)
            bottomView?.addGestureRecognizer({
                let panGesture = UIPanGestureRecognizer(target: self, action: #selector(onPan))
                panGesture.delegate = self
                return panGesture
            }())
        }
        
        private var stateString: String = "" {
            didSet {
                if stateString != oldValue {
                    print("State changed to \(stateString)")
                }
            }
        }
        
        @objc private func onPan(_ sender: UIGestureRecognizer) {
            switch sender.state {
            case .began: stateString = "begin"
            case .changed: stateString = "changed"
            case .ended: stateString = "ended"
            case .cancelled: stateString = "canceled"
            default: stateString = "some thing else"
            }
        }
    
    }
    
    
    extension ViewController: UIGestureRecognizerDelegate {
        
        func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
            return topView.bounds.contains(touch.location(in: topView)) == false
        }
        
    }
    

    A gesture only works when started out of the green view. Once a gesture has started then events will be triggered normally as they should, that includes within the green view.