iOS开发如何给UIButton addTarget传参 解决按钮点击无响应问题
Bottom Sheet内自定义按钮点击无响应问题修复
问题根因
从现有代码看,点击无响应是几个常见问题叠加导致的:
- 混用了Storyboard实例和代码新建实例:你已经通过Storyboard拖线绑定了
openPage按钮,又在CollectionView配置逻辑中通过let button = SheetOpenPageButton()新建了独立按钮实例,这个新实例既没有被添加到视图层级,也没有设置布局,屏幕上实际显示的是Storyboard生成的按钮,你给新建实例绑定的点击事件自然不会触发 - 按钮创建方式不规范:代码创建UIButton时未指定
.custom类型,系统默认的system样式可能干扰点击事件响应 - 底部弹窗命中测试问题:Bottom Sheet场景下经常出现子视图超出父视图bounds的情况,UIKit默认不会响应bounds外的点击事件,哪怕视图可见也无法触发交互
- 跳转逻辑顺序冲突:现有代码先执行导航push再dismiss弹窗,容易导致导航栈操作失效,同时自定义按钮中声明的
navigationController属性从未赋值,直接调用会拿到nil
分步修复方案
1. 统一按钮实例,不要重复创建
如果使用Storyboard布局的按钮,直接使用@IBOutlet连线的实例配置属性、绑定事件,不要重复新建对象:
// 删除 let button = SheetOpenPageButton() 这行重复创建的代码 // 直接操作Storyboard连线的实例 openPage.tag = cell.id ?? 1 openPage.addTarget(self, action: #selector(goToRestuarantFromStory(_:)), for: .touchUpInside)
如果需要动态在CollectionViewCell中生成按钮,先删除Storyboard中多余的按钮和对应@IBOutlet连线,创建按钮后必须添加到视图层级并设置布局:
// 创建按钮时指定.custom类型,避免系统样式干扰 let button = SheetOpenPageButton(type: .custom) button.tag = cell.id ?? 1 button.addTarget(self, action: #selector(goToRestuarantFromStory(_:)), for: .touchUpInside) // 必须添加到父视图,建议加到cell的contentView上 cell.contentView.addSubview(button) // 补全按钮的布局约束,确保位置尺寸正确 button.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ button.centerXAnchor.constraint(equalTo: cell.contentView.centerXAnchor), button.centerYAnchor.constraint(equalTo: cell.contentView.centerYAnchor), button.widthAnchor.constraint(equalToConstant: 120), button.heightAnchor.constraint(equalToConstant: 44) ])
2. 补全自定义按钮的基础配置
优化SheetOpenPageButton类,删除冗余属性,补全初始化默认配置:
class SheetOpenPageButton: UIButton { // 删除无用的navigationController属性,避免误用nil实例 override init(frame: CGRect) { super.init(frame: frame) setupCommonConfig() } required init?(coder: NSCoder) { super.init(coder: coder) setupCommonConfig() } private func setupCommonConfig() { isUserInteractionEnabled = true backgroundColor = UIColor(named: "CustomGray") // 关闭高亮时的系统默认样式调整 adjustsImageWhenHighlighted = false } override var isSelected: Bool { didSet { backgroundColor = isSelected ? UIColor(named: "CustomRed") : UIColor(named: "CustomGray") } } }
3. 修复Bottom Sheet点击命中问题
如果按钮添加到层级后仍然无法点击,给Bottom Sheet的容器视图重写命中测试方法,允许响应超出bounds的子视图点击:
class BottomSheetContainerView: UIView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { guard isUserInteractionEnabled, !isHidden, alpha > 0.01 else { return nil } // 倒序遍历子视图,优先响应最上层的交互元素 for subview in subviews.reversed() { let convertedPoint = subview.convert(point, from: self) if let responder = subview.hitTest(convertedPoint, with: event) { return responder } } return super.hitTest(point, with: event) } }
4. 调整跳转执行顺序
将弹窗关闭和页面跳转的逻辑顺序调整,避免导航栈冲突,不要依赖未赋值的属性拿导航控制器:
@objc func goToRestuarantFromStory(_ sender : UIButton) { let targetPageId = sender.tag // 先移除弹窗相关视图 removeSubview() removeSubviewSpb() // 弹窗dismiss完成后再执行页面跳转 vc.dismiss(animated: true) { guard let restaurantVC = UIStoryboard(name: "Cafe", bundle: .main) .instantiateViewController(withIdentifier: "RestuarantViewController") as? RestuarantViewController else { return } restaurantVC.networkId = targetPageId // 拿当前KeyWindow的根导航控制器执行push,避免拿错实例 guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }), let rootNav = keyWindow.rootViewController as? UINavigationController else { return } rootNav.pushViewController(restaurantVC, animated: true) } }
内容的提问来源于stack exchange,提问作者Mariam Sargsyan
相关产品推荐
相关产品推荐

