如何为UIView添加TapGesture并让ViewController响应tapHandler?
解决UIView中添加点击手势并触发ViewController方法的问题
嘿,我来帮你搞定这个手势识别的问题~你的原代码有几个关键错误导致无法正常工作,我先帮你梳理问题,再给出两种靠谱的实现方案。
原代码的问题分析
- Target传错了:你把
ViewController类作为target传入,但UITapGestureRecognizer需要的是ViewController的实例对象,而不是类型本身。类方法才会用类作为target,但你要调用的是实例方法tapHandler,所以这里完全不对。 - Action写法错误:
#selector(ViewController.tapHandler(view: self))这种写法不符合selector的规范,selector只需要方法的签名,不能直接传递参数,正确的写法应该是#selector(ViewController.tapHandler(view:))(但即使这样,因为target是类,也无法调用实例方法)。 - 代码位置错误:
self.addGestureRecognizer(tab)写在了init方法外面,这会导致编译错误,必须把添加手势的代码放在init方法内部。
方案一:给UIView添加弱引用的ViewController属性(直接关联)
这种方式适合UIView明确知道自己所属的ViewController类型的场景,注意用weak避免循环引用(因为ViewController已经持有UIView,UIView再强引用ViewController会导致内存泄漏)。
首先自定义你的UIView:
class CustomTapView: UIView { // 用weak修饰,避免循环引用 weak var tapDelegate: ViewController? required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupTapGesture() } override init(frame: CGRect) { super.init(frame: frame) setupTapGesture() } private func setupTapGesture() { // 先给当前UIView添加手势,自己作为中间处理者 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) self.addGestureRecognizer(tapGesture) // 确保UIView开启用户交互(默认是开启的,但保险起见加上) self.isUserInteractionEnabled = true } @objc private func handleTap(_ gesture: UITapGestureRecognizer) { // 转发手势事件到ViewController的tapHandler方法 tapDelegate?.tapHandler(view: self) } }
然后在ViewController中关联这个属性:
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 假设你的CustomTapView是通过Storyboard/XIB创建的,或者代码实例化的 if let customView = self.view as? CustomTapView { customView.tapDelegate = self } } // 确保方法加上@objc,否则无法被selector识别 @objc func tapHandler(view: UIView) { print("点击了UIView,触发了ViewController的方法!") // 这里写你的业务逻辑 } }
方案二:用闭包实现解耦(更灵活)
如果不想让UIView依赖ViewController的类型,闭包是更好的选择,它更解耦,UIView不需要知道谁会处理这个点击事件。
自定义UIView的代码:
class CustomTapView: UIView { // 定义一个闭包,参数是被点击的UIView var onTap: ((UIView) -> Void)? required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupTapGesture() } override init(frame: CGRect) { super.init(frame: frame) setupTapGesture() } private func setupTapGesture() { let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) self.addGestureRecognizer(tapGesture) self.isUserInteractionEnabled = true } @objc private func handleTap(_ gesture: UITapGestureRecognizer) { // 触发闭包,把当前View传出去 onTap?(self) } }
ViewController中的使用:
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() if let customView = self.view as? CustomTapView { // 绑定闭包,注意用[weak self]避免循环引用 customView.onTap = { [weak self] tappedView in self?.tapHandler(view: tappedView) } } } @objc func tapHandler(view: UIView) { print("通过闭包触发了ViewController的点击处理方法!") // 业务逻辑写这里 } }
额外注意事项
- 一定要确保UIView的
isUserInteractionEnabled属性为true,如果这个属性是false,手势识别不会生效。 - 所有被selector调用的方法都要加上
@objc修饰,否则Swift的方法无法被Objective-C运行时识别(因为UITapGestureRecognizer是基于Objective-C的API)。 - 处理闭包或者属性引用时,记得用
weak self避免循环引用,防止内存泄漏。
内容的提问来源于stack exchange,提问作者True Hekka
相关产品推荐
相关产品推荐

