You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:36:23