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

循环生成UIButton与UIView后,如何在按钮点击事件传递对应UIView

解决UIButton点击关联对应UIView的几种实用方案

嘿,这个场景在iOS开发里太常见了,循环生成的按钮要对应到视图,光靠tag确实不够灵活,给你分享几个亲测好用的方案:

方案一:用关联对象给UIButton绑定对应UIView

这是比较灵活的方式,利用Objective-C运行时特性,给UIButton扩展一个自定义属性来存储对应的UIView:

首先导入运行时框架:

import ObjectiveC

给UIButton添加关联属性:

private var associatedViewKey = 0
extension UIButton {
    var linkedView: UIView? {
        get {
            return objc_getAssociatedObject(self, &associatedViewKey) as? UIView
        }
        set {
            objc_setAssociatedObject(self, &associatedViewKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

修改循环代码,把生成的myView绑定到按钮上:

for (key, value) in myStringsArray { 
    let myButton = UIButton() 
    let myView = UIView() 
    // 注意你原代码里写的是panelButton,应该是myButton哦
    myButton.tag = value 
    myButton.linkedView = myView // 绑定对应的视图
    myButton.addTarget(self, action: #selector(onMyButtonClick), for: .touchUpInside) 
    // 记得把button和view添加到父视图中
}

最后修改点击事件,直接获取绑定的视图并切换隐藏状态:

@objc func onMyButtonClick(sender: UIButton) { 
    sender.linkedView?.isHidden = !(sender.linkedView?.isHidden ?? false)
}

方案二:用闭包实现按钮点击(更Swift风格的方式)

如果不想用Selector和关联对象,可以封装一个支持闭包点击的UIButton,循环里直接处理对应视图的逻辑:

先扩展UIButton添加闭包点击能力:

extension UIButton {
    private struct AssociatedKeys {
        static var tapClosure = "tapClosure"
    }

    typealias TapHandler = () -> Void

    private var tapHandler: TapHandler? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.tapClosure) as? TapHandler
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.tapClosure, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    func addTapHandler(handler: @escaping TapHandler) {
        tapHandler = handler
        addTarget(self, action: #selector(handleTap), for: .touchUpInside)
    }

    @objc private func handleTap() {
        tapHandler?()
    }
}

循环里直接给按钮绑定闭包,直接操作当前的myView:

for (key, value) in myStringsArray { 
    let myButton = UIButton() 
    let myView = UIView() 
    // 闭包里直接操作当前循环的myView,逻辑更直观
    myButton.addTapHandler { [weak self] in
        myView.isHidden = !myView.isHidden
        // 如果需要访问self的属性,记得用weak self避免循环引用
    }
    // 添加到父视图...
}

这种方式不用单独写Selector方法,逻辑都集中在循环里,还能避免tag冲突的问题,非常推荐。

方案三:用字典存储tag和UIView的映射关系

如果还是想依赖tag实现,可以把生成的UIView存到字典里,用tag作为key:

首先定义一个字典属性:

var viewTagMap = [Int: UIView]()

循环里把View存入字典:

for (key, value) in myStringsArray { 
    let myButton = UIButton() 
    let myView = UIView() 
    let tag = value // 假设value是Int类型
    myButton.tag = tag 
    viewTagMap[tag] = myView // 存储tag与视图的映射
    myButton.addTarget(self, action: #selector(onMyButtonClick), for: .touchUpInside) 
    // 添加到父视图...
}

点击事件里通过tag取出对应View:

@objc func onMyButtonClick(sender: UIButton) { 
    if let targetView = viewTagMap[sender.tag] {
        targetView.isHidden = !targetView.isHidden
    }
}

这种方式要注意tag必须唯一,如果myStringsArray里的value有重复,会覆盖之前的视图,使用前要确保tag的唯一性。

以上几种方案都能完美解决你的需求,个人更推荐方案二,更贴合Swift的编程习惯,也能避开很多潜在的坑~

内容的提问来源于stack exchange,提问作者Dylan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 23:27:34