Event response priorities for gesture recognizers, UIControl, and UIButton

59 views Asked by At

I have a parent view with a gesture recognizer added. The parent view contains a UIButton and a UIControl, with corresponding actions added respectively.

The code is as follows

class MyViewController: UIViewController {
    
     private lazy var parentView = UIView()
     private lazy var button = UIButton(frame: .zero)
     private lazy var control = UIControl(frame: .zero)
    
     override func viewDidLoad() {
         super.viewDidLoad()
        
         view.backgroundColor = .white
         view.addSubview(parentView)
         parentView.addSubview(button)
         parentView.addSubview(control)
        
         parentView.backgroundColor = .red
         button.backgroundColor = .yellow
         control.backgroundColor = .blue
        
         let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleParentViewTapped))
         parentView.addGestureRecognizer(tapGesture)
         button.addTarget(self, action: #selector(handleButtonClicked), for: .touchUpInside)
         control.addTarget(self, action: #selector(handleControlClicked), for: .touchUpInside)
        
         parentView.snp.makeConstraints { make in
             make.edges.equalToSuperview()
         }
         button.snp.makeConstraints { make in
             make.leading.top.equalToSuperview()
             make.size.equalToSuperview().multipliedBy(0.5)
         }
         control.snp.makeConstraints { make in
             make.trailing.bottom.equalToSuperview()
             make.size.equalToSuperview().multipliedBy(0.5)
         }
     }
    
     @objc func handleParentViewTapped() {
         print("view tapped")
     }
    
     @objc func handleButtonClicked() {
         print("button clicked")
     }
    
     @objc func handleControlClicked() {
         print("UIControl clicked")
     }

}

I clicked UIButton and UIControl successively, and the console printing sequence is as follows

button clicked
view tapped

As you can see, clicking a UIButton can trigger the action corresponding to the UIButton, but clicking a UIControl will trigger the callback of the gesture recognizer.

Next, I set the cancelsTouchesInView of the parent view's gesture recognizer to false. This time, the callbacks of the gesture recognizer, UIButton, and UIControl will all be called.

view tapped
button clicked
view tapped
UIControl clicked

my question is

  1. Since UIButton also inherits from UIControl, why is the event response priority of UIButton higher than the gesture recognizer of the parent view, but UIControl is lower than the gesture recognizer of the parent view?
  2. If I have a custom UIControl and want to achieve the same priority effect as a UIButton, how should I achieve it?
  3. I know that if the cancelsTouchesInView of the gesture recognizer is set to false, the click event will continue to be passed to the UIControl, so the UIControl can respond to the event. But why can both UIButton and gesture recognizers respond to events after cancelsTouchesInView is set to false?
0

There are 0 answers