如何向通用 UITapGestureRecognizer 添加参数?
How to add parameters to a generic UITapGestureRecognizer?
问题是:我怎样才能制作一个通用版本的 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所做的那样。
问题是,我有时需要将参数传递给此函数。
例如,如果我想传递一个对象,我愿意这样做。然后我可以通过应用程序在全球范围内重用这个功能。
我试过的所有方法都不起作用,我可以提供一些这样的代码:
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)
但我有点迷路了。
首先,target/action模式的selector
有两种固定形式:
- 一个没有参数的函数
- 具有 一个 参数的函数代表
sender
,触发操作的对象。
但是您可以在子class中添加属性并在(自定义)init 方法中传递参数。
子class中的泛型与框架作斗争,因此自定义字典(您也可以只使用 Any
)是更好的选择。
例如,除了目标和操作之外,class 有一个 userInfo
字典和一个 onClick
闭包。 init
方法调用 super
来调用点击识别器的指定初始化器。
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?()
}
}
更通用的实现是在onClick
闭包中传递userInfo
。
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)
}
}
问题是:我怎样才能制作一个通用版本的 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所做的那样。
问题是,我有时需要将参数传递给此函数。 例如,如果我想传递一个对象,我愿意这样做。然后我可以通过应用程序在全球范围内重用这个功能。
我试过的所有方法都不起作用,我可以提供一些这样的代码:
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)
但我有点迷路了。
首先,target/action模式的selector
有两种固定形式:
- 一个没有参数的函数
- 具有 一个 参数的函数代表
sender
,触发操作的对象。
但是您可以在子class中添加属性并在(自定义)init 方法中传递参数。
子class中的泛型与框架作斗争,因此自定义字典(您也可以只使用 Any
)是更好的选择。
例如,除了目标和操作之外,class 有一个 userInfo
字典和一个 onClick
闭包。 init
方法调用 super
来调用点击识别器的指定初始化器。
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?()
}
}
更通用的实现是在onClick
闭包中传递userInfo
。
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)
}
}