如何向泛型UITapGestureRecognizer添加参数?

How to add parameters to a generic UITapGestureRecognizer?

提问人:Mathieu Rios 提问时间:6/3/2021 最后编辑:Mathieu Rios 更新时间:6/3/2021 访问量:557

问:

问题是:我怎样才能制作一个可以在我的应用程序中使用的 UITapGestureRecognizer 的通用版本。

如果我不想传递任何参数,这很简单:

class ClickListener: UITapGestureRecognizer {
    var onClick : (() -> Void)? = nil
}


// MARK: UIView Extension
extension UIView {
    
    func setOnClickListener(action :@escaping () -> Void){
        let tapRecogniser = ClickListener(target: self, action: #selector(onViewClicked(sender:)))
        tapRecogniser.onClick = action
        self.addGestureRecognizer(tapRecogniser)
    }
    
    @objc func onViewClicked(sender: ClickListener) {
        if let onClick = sender.onClick {
            onClick()
        }
    }
  
}

正如 Sunneet Agrawal 所做的那样。

问题是,我有时需要将参数传递给这个函数。 例如,如果我想传递一个 Object,我想这样做。然后我可以通过应用程序在全球范围内重用这个功能。

我尝试的所有方法都不起作用,我可以提供一些代码,如下所示:

class ClickListener<T: Any>: UITapGestureRecognizer {
    var onClick : (() -> Void)? = nil
    var clickedObject: Any
    
    override init(onClick: (() -> Void), clickedObject: Any, target: self, action: ???){
        self.onClick = onClick
        self.clickedObject = clickedObject
        super.init(target: self, action: ???)
    }
}

extension UIView {
    
    func setOnClickListener(action :@escaping () -> Void){
        let tapRecogniser = ClickListener(// Init here)
        tapRecogniser.onClick = action( // parameter here)
        self.addGestureRecognizer(tapRecogniser)
    }
    
    @objc func onViewClicked(sender: ClickListener) {
        if let onClick = sender.onClick {
            onClick(// with parameter passed)
        }
    }
  
}

// Then in my VC

UIView.setOnclickListener(action: anyFunction, clickedObject: anyObject)

但我在那里有点迷茫。

iOS Swift UITaPgesturerecognizer

评论

1赞 Duncan C 6/3/2021
参数到什么功能?到点击手势识别器调用的目标/操作?对于已添加到自定义手势识别器的“onClick”闭包?这两个都有解决方案。
1赞 Duncan C 6/3/2021
在我看来,向点击手势识别器添加一个闭包,并让点击手势识别器向其目标发送一个操作,然后调用手势识别器上的闭包,这对我来说似乎很奇怪。
0赞 Mathieu Rios 6/3/2021
我试图在我的问题中添加更多内容,以便更容易理解。为了清楚起见,我希望能够将点击手势识别器添加到 UIViews 并向其传递参数。例如,我希望能够将 tap 函数添加到传递用户对象的 UIView 中,然后我可以在函数中使用该对象的特定变量

答:

2赞 vadian 6/3/2021 #1

首先,目标/行动模式有两种固定形式:selector

  • 不带参数的函数
  • 一个函数,其中包含一个参数,表示触发操作的对象。sender

但是您可以在子类中添加属性,并在(自定义)init 方法中传递参数。

子类中的泛型与框架作斗争,因此自定义字典(您也可以使用)是更好的选择。Any

例如,除了 target 和 action 之外,该类还有一个字典和一个闭包。该方法调用以调用点击识别器的指定初始值设定项。userInfoonClickinitsuper

class ClickListener: UITapGestureRecognizer {
    var onClick : (() -> Void)?
    var userInfo: [String:Any]?
    
    init(target: Any?, action: Selector?, userInfo: [String:Any]? = nil, onClick: (() -> Void)? = nil) {
        self.userInfo = userInfo
        self.onClick = onClick
        super.init(target: target, action: action)
    }
}

你可以使用它

extension UIView {
    
    func setOnClickListener(action :@escaping () -> Void){
        let tapRecogniser = ClickListener(target: self, action: #selector(onViewClicked), userInfo: ["message":"Hello World"], onClick: action)
        self.addGestureRecognizer(tapRecogniser)
    }
    
    @objc func onViewClicked(_ sender: ClickListener) {
        if let userInfo = sender.userInfo,
            let message = userInfo["message"] as? String {
            print(message)
        }
        sender.onClick?()
    }
    
}

通用的实现是将 in 传递到闭包中。userInfoonClick

class ClickListener: UITapGestureRecognizer {
    var onClick : (([String:Any]?) -> Void)?
    var userInfo: [String:Any]?
    
    init(target: Any?, action: Selector?, userInfo: [String:Any]? = nil, onClick: (([String:Any]?) -> Void)?) {
        self.userInfo = userInfo
        self.onClick = onClick
        super.init(target: target, action: action)
    }
}

extension UIView {
    
    func setOnClickListener(userInfo: [String:Any], action :@escaping ([String:Any]?) -> Void){
        let tapRecogniser = ClickListener(target: self, action: #selector(onViewClicked), userInfo: userInfo, onClick: action)
        self.addGestureRecognizer(tapRecogniser)
    }
    
    @objc func onViewClicked(_ sender: ClickListener) {
        sender.onClick?(sender.userInfo)
    }
    
}