如何将闭包作为动作传递给添加到 UIView 的点击手势?

How to pass a closure as action to tap gesture added to a UIView?

我想要一个 UIView 上的点击功能,但我不知道如何在函数的第一张图片中传入那个闭包:

首先:我强烈建议在您的问题中添加代码片段而不是屏幕截图。

您需要为 UITapGestureRecognizer 中的操作参数传递 Selector 而不是 () -> () 闭包:

extension UIView {
    func onClick(target: Any, _ selector: Selector) {
        isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: target, action: selector)
        addGestureRecognizer(tap)
    }
}

此外,请记住,此时您必须为 tap 实例设置适当的 target,这意味着它 而不是 selfUIView 扩展中(在您的代码中实现);相反,您必须将其作为参数传递给 onClick 方法。

用法:

在你的ViewController中:

likesImg.onClick(target: self, #selector(likesImgClicked))

@objc private func likesImgClicked() {
    print(#function)
}

当说 likesImg.onClick(target: self 时:这里的 self 表示 ViewController 本身,而不是 UIView 扩展,这是正确的目标,因为 likesImgClicked 在ViewController 但不在 UIView 扩展中。


更新:

如果你坚持传递闭包的方法,你可以按照这个解决方案:

将您的 UIView 扩展实现为:

extension UIView {
    private struct OnClickHolder {
        static var _closure:()->() = {}
    }

    private var onClickClosure: () -> () {
        get { return OnClickHolder._closure }
        set { OnClickHolder._closure = newValue }
    }


    func onClick(target: Any, _ selector: Selector) {
        isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: self, action: selector)
        addGestureRecognizer(tap)
    }

    func onClick(closure: @escaping ()->()) {
        self.onClickClosure = closure

        isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: self, action: #selector(onClickAction))
        addGestureRecognizer(tap)
    }

    @objc private func onClickAction() {
        onClickClosure()
    }
}

用法:

在你的ViewController中:

likesImg.onClick {
    print("Hello!!")
}

重要提示:

感谢 @Josh Caswell 的以下说明:

Note that the private struct gets you one storage location for the entire program. If you try to set a handler on more than one view, the second will overwrite the first.

我刚刚根据一些答案重新设计了 swift 点击侦听器 android 样式。使用起来非常简单:

yourView.setClickListener {
    // do some actions here!
}

将此添加到您的扩展文件中:

final class ClickListener: UITapGestureRecognizer {
    private var action: () -> Void

    init(_ action: @escaping () -> Void) {
        self.action = action
        super.init(target: nil, action: nil)
        self.addTarget(self, action: #selector(execute))
    }

    @objc private func execute() {
        action()
    }
}

extension UIView {
    func setClickListener(_ action: @escaping () -> Void) {
        self.isUserInteractionEnabled = true
        let click = ClickListener(action)
        self.addGestureRecognizer(click)
    }
}

我正在使用 Xcode 11.7 和 Swift 5.2

我创建了一个通用的按钮操作。请参考以下代码

    import UIKit


    func customBarButton(_ target: Any, selector: Selector, controlEvent: UIControl.Event, buttonImage: String) -> UIBarButtonItem{
        let customButton = UIButton(type: .custom)
        customButton.setImage(UIImage(named: buttonImage), for: .normal)
        customButton.frame = CGRect(x: 0, y: 0, width: 24, height: 24)
        customButton.addTarget(target, action: selector, for: controlEvent)
        let filterItem = UIBarButtonItem(customView: customButton)

        return filterItem
    }

我在 viewcontroller 文件中使用了上述代码。

在 viewdidload 中初始化。

    let searchItem = customBarButton(self, selector: #selector(didTapSearchButton(_:)), controlEvent: .touchUpInside, buttonImage: "search")
    
    navigationItem.rightBarButtonItems = [searchItem]

触摸按钮时调用的函数:

@objc func didTapSearchButton(_ sender: Any){
 //enter code here
}