UIButton 不受 UITapGestureRecoginzer 的影响。

UIButton is not affected by UITapGestureRecoginzer.

我有一个 UIImageView (userInteractionEnabled) UIButtonUITextField 都是 superview 的子视图,其中添加了一个 UITapGestureRecognizer。所以我的 superviewUIImageView 响应 来点击手势但是 UIButtonUITextField 忽略 它。这是我的错添加到 superview 的 UITapGestureRecognizer 策略吗?请问有人知道这种情况吗?

这是我的带有视图子视图和手势识别器的代码

 @objc   func tapBlurButton(_ sender: UITapGestureRecognizer) {
    print("Please Help!")
    endEditing(true)

}


override init(frame: CGRect) {
    super.init(frame: frame)
   //     backgroundColor = UIColor.green

    addSubview(logoImageView)
   // addSubview(skipButton)
   addSubview(emailTextField)
   addSubview(passwordTextField)
    addSubview(loginButton)
     observeKeyboardNotifications()


 //   logoImageView.translatesAutoresizingMaskIntoConstraints = false
    logoImageView.anchorWithConstantsToTop(centerYAnchor, left: nil  , bottom: nil, right: nil, topConstant: -230, leftConstant: 0, bottomConstant: 0, rightConstant: 0)
    logoImageView.widthAnchor.constraint(equalToConstant: 160).isActive = true
    logoImageView.heightAnchor.constraint(equalToConstant: 160).isActive = true
    logoImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true

    emailTextField.anchorWithConstantsToTop(logoImageView.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 8, leftConstant: 32, bottomConstant: 0, rightConstant: 32)
    emailTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
    passwordTextField.anchorWithConstantsToTop(emailTextField.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 8, leftConstant: 32, bottomConstant: 0, rightConstant: 32)
    passwordTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
    loginButton.anchorWithConstantsToTop(passwordTextField.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 16, leftConstant: 32, bottomConstant: 0, rightConstant: 32)
    loginButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
    isUserInteractionEnabled = true
    addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(LoginCell.tapBlurButton(_:))))
    isUserInteractionEnabled = true

 }

我看到其他答案,他们只是告诉如何解决它,但他们没有说明发生这种情况的真正原因,而且没有人参考确切说明此问题的文档。所以我的问题不是问如何避免它或如何解决它,我想知道它为什么会发生,当我怀疑 UIkit 这样做时我是对的所以这不是我的错或者我错了错过了什么?

Apple 有一篇非常简单且有用的文章。要了解您想要什么,您应该查看 Responder Chain 概念。

Understanding Event Handling, Responders, and the Responder Chain

基本上,如果您想了解为什么您的 UIImageView 响应 点击,但 UIButtonUITextField 不要这样做,有一个简单的解释。 UIButtonUITextFieldUIControl的子类,UIImageView不是,只是UIResponder的子类。所以,每个UIControl都使用Target-Action机制,但是UIResponder不这样做。

UIControl docs

文档说:

Controls communicate directly with their associated target object using action messages. When the user interacts with a control, the control calls the action method of its target object—in other words, it sends an action message to its target object. Action messages are not events, but they may still take advantage of the responder chain. When the target object of a control is nil, UIKit starts from the target object and walks the responder chain until it finds an object that implements the appropriate action method.

因此,这意味着 默认情况下 当您单击 UIControl 对象时,它不会将该事件传播到超级视图来处理它。控件覆盖默认 UIResponder 行为。但是当你点击一个UIResponder的时候,它会将事件发送给superview去处理,touch落空了。因此,UIKit 会执行此操作,而通常的 UITapGestureRecognizers 默认情况下不会经过 UIControls,因为控件具有其预设事件集并使用另一种机制来处理它们。但是当您禁用 UIControl 与用户点击交互的能力时,您的 superview 点击手势识别器将会响应。

在你的例子中,如果你设置了它,即使你按下按钮,你的 func tapBlurButton(_ sender: UITapGestureRecognizer) 也会被调用,因为那个按钮不会尝试处理事件,触摸只会落到超级视图。

loginButton.isUserInteractionEnabled = false