【问题标题】:Propagating touch event through view hierarchy (UIButton inside UIView)通过视图层次结构传播触摸事件(UIView 内的 UIButton)
【发布时间】:2024-04-27 17:55:01
【问题描述】:

很确定这是一个简单的问题,但仍然无法在 Internet 上找到任何类似的东西——这又是一个相信这不是问题的理由。无论如何!

我怎样才能put a UIButton inside a UIView 和添加UITapGestureRecognizer 在视图上调用此视图中的函数,同时仍执行按钮操作?

我有什么:

  • 在按钮内部点击只会执行按钮操作。
  • 在按钮外部点击只会执行查看功能。

我想要什么:

  • 在按钮内部点击会执行按钮操作和视图功能。
  • 在按钮外部点击只会执行查看功能。

更新(我使用的代码):

import UIKit
import AwesomeFramework

class View: UIView {

    let button = UIButton()
    let awesomeObject = AwesomeFramework.AwesomeObject()

    @objc func a(_ sender: Any) {
        // never gets called
        print("a")
    }

    init() {
        super.init(frame: .zero)

        button.translatesAutoresizingMaskIntoConstraints = false
        addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: centerXAnchor),
            button.centerYAnchor.constraint(equalTo: centerYAnchor),
            button.widthAnchor.constraint(equalTo: widthAnchor),
            button.heightAnchor.constraint(equalTo: heightAnchor),
            ])

        button.addTarget(awesomeObject, action: #selector(awesomeAction), for: .touchUpInside) // awesomeAction prints "b"

        let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(a(_:)))
        addGestureRecognizer(gestureRecognizer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

点击我想要的按钮:

b
a

a
b

我明白了:

b

更新:对示例进行了一些限制,例如:

  • 按钮在我无权访问的框架中触发操作
  • 实际上有很多按钮和其他点击接收元件。我不想对所有人都使用 a-function(我也不能因为某些元素管理自己的识别器)

【问题讨论】:

    标签: ios cocoa-touch uibutton uitapgesturerecognizer


    【解决方案1】:

    在 UITapGestureRecognizer 的选择器中,您可以检查哪个视图是从哪个视图触发的。由于您可以访问视图,因此您可以检查发送视图的标签并确定它是否由您的按钮触发。

    你可以这样做:

    @objc func a(_ sender: Any) {
        if let gesture = sender as? UITapGestureRecognizer, let v = gesture.view, v.tag == self.button.tag {
            return //since it has the tag same as that you had set for button, return
        }
        // else do what you wanted to.
    }
    

    您可以将选择器链接为:

    #selector(a(_:))
    

    并定义为:

    func a(_ sender: Any) { .....}
    

    请务必通过以下方式标记您的按钮:

    self.button.tag = 9 //(or any number you prefer)
    

    【讨论】:

    • 非常感谢!我认为这可能对我有所帮助,即使问题中添加了信息。
    • 遗憾的是 @objc func a(_ sender: Any) 没有被触发(就像 b() 一样,并且触摸不会传播到 a())。所以我不能执行那个检查。
    • @TrevorFreeman 你把这个:UITapGestureRecognizer(target: self, action: #selector(a)) 改成这个:UITapGestureRecognizer(target: self, action: #selector(a(_:)))
    • 是的,我做到了(所以希望这条评论的长度至少为 15 个字符,所以我也声明了这个事实)
    • @TrevorFreeman 你能发布你实例化这个视图的代码并将它作为子视图添加到父视图吗?
    【解决方案2】:

    一个按钮可以有多个目标。告诉按钮同时触发ab

    button.addTarget(self, action: #selector(a), for: .touchUpInside)
    button.addTarget(self, action: #selector(b), for: .touchUpInside)
    

    如果用户将手指放在按钮上,然后在释放之前将其拖出按钮会怎样?如果您希望它也触发a 操作,也可以这样做:

    button.addTarget(self, action: #selector(a), for: .touchUpOutside)
    

    【讨论】:

    • 谢谢! .touchUpOutside 的好提示!我想我将不得不找到另一种方法,因为我确实有很多按钮和其他敏感元素(相应地更新了问题)。