如何从模态展示的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
相关产品推荐
相关产品推荐

