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

如何从模态展示的ViewController及其中TableCell弹出Action Sheet?

解决模态ViewController中TableViewCell按钮触发ActionSheet的问题

我来帮你把这个功能完整实现并理顺逻辑~你的代理思路是对的,接下来咱们一步步补全代码:

1. 完善TableViewCell的代码

先把你的tableCell类补全,确保按钮点击能正确调用代理方法:

protocol MyDelegate: class {
    func showDropDownMenu(for cell: UITableViewCell) // 建议加上cell参数,方便后续定位触发按钮的单元格
}

class tableCell: UITableViewCell {
    weak var delegate: MyDelegate?
    @IBOutlet weak var dropDownButton: UIButton! // 记得给按钮加IBOutlet关联
    
    @IBAction func dropDownButton(_ sender: UIButton) {
        // 点击按钮时调用代理方法
        delegate?.showDropDownMenu(for: self)
    }
}

这里给代理方法加了cell参数,方便你后续获取触发按钮的单元格位置(比如拿到indexPath),如果不需要也可以去掉。

2. 在ViewControllerA中实现代理协议

让ViewControllerA遵守MyDelegate协议,在cellForRowAt方法里给cell设置代理,最后实现代理方法展示ActionSheet:

class ViewControllerA: UIViewController, UITableViewDataSource, UITableViewDelegate, MyDelegate {
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册cell(如果是xib创建的话)
        tableView.register(UINib(nibName: "tableCell", bundle: nil), forCellReuseIdentifier: "tableCell")
        tableView.dataSource = self
        tableView.delegate = self
    }
    
    // MARK: - UITableView DataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5 // 替换成你的实际数据数量
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! tableCell
        cell.delegate = self // 关键:给cell设置代理
        return cell
    }
    
    // MARK: - MyDelegate
    func showDropDownMenu(for cell: UITableViewCell) {
        // 创建ActionSheet
        let actionSheet = UIAlertController(title: "选择操作", message: nil, preferredStyle: .actionSheet)
        
        // 添加操作选项
        actionSheet.addAction(UIAlertAction(title: "选项1", style: .default, handler: { _ in
            // 处理选项1的逻辑
            print("点击了选项1")
        }))
        
        actionSheet.addAction(UIAlertAction(title: "选项2", style: .default, handler: { _ in
            // 处理选项2的逻辑
            print("点击了选项2")
        }))
        
        actionSheet.addAction(UIAlertAction(title: "取消", style: .cancel))
        
        // 关键:适配iPad和iOS13+的显示问题
        if let popoverController = actionSheet.popoverPresentationController {
            // 把按钮作为弹出的锚点,让ActionSheet指向按钮显示
            popoverController.sourceView = cell.dropDownButton
            popoverController.sourceRect = cell.dropDownButton.bounds
            popoverController.permittedArrowDirections = .up
        }
        
        // 展示ActionSheet
        present(actionSheet, animated: true)
    }
}

几个关键注意点:

  • 代理的weak修饰:一定要给delegate加weak,避免循环引用(ViewController持有tableView,tableView持有cell,cell强引用ViewController会导致内存泄漏)。
  • iPad适配:iOS13+的ActionSheet在iPad上默认是popover样式,必须设置popoverPresentationController的sourceView或sourceRect,否则会崩溃。
  • 获取触发源:如果需要知道是哪个单元格的按钮被点击,可以通过tableView.indexPath(for: cell)拿到indexPath,进而处理对应的数据逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:01:04