Swift中如何通过字符串编程调用UIButton实现点击跳转
实现方案
现有代码存在3个明显问题,会导致点击跳转完全不符合预期:
- 第二个集合视图的按钮
restorationIdentifier赋值漏了插值反斜杠,存进去的是固定字符串(indexPath.row),根本转不成整数,点击后直接走失败分支 - 第一个集合视图的按钮ID计算逻辑写反了,给第一个CV的按钮ID统一加了6,导致第一个CV的ID全在6-11区间,
id < 6的判断永远不成立,点第一个CV的按钮全触发第二个跳转逻辑 - 用
restorationIdentifier存索引本身就不是常规写法,而且跳转逻辑写死了两个固定segue,没法匹配每个按钮对应的独立闪卡内容
模拟器运行效果参考:
具体实现步骤
1. 清理错误的点击绑定
删掉现有写的@IBAction func Buttons(_ sender: Any)方法,不要靠给按钮打恢复ID的方式传索引,cell复用的时候很容易出内容错乱。
2. 修正cell配置逻辑
两个Cell的UI样式配置完全重复,可以后续合并成一个通用Cell,先修正cellForItemAt里的赋值错误,正确绑定按钮事件:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if collectionView == firstCV { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "firstCell", for: indexPath) as! FirstCollectionViewCell let contentTitle = firstData[indexPath.item] cell.buttonOne.setTitle(contentTitle, for: .normal) cell.buttonOne.tag = indexPath.item cell.buttonOne.addTarget(self, action: #selector(collectionButtonTapped(_:)), for: .touchUpInside) return cell } let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "secondCell", for: indexPath) as! SecondCollectionViewCell let contentTitle = secondData[indexPath.item] cell.buttonTwo.setTitle(contentTitle, for: .normal) // 第二个分组的tag加6,和第一个分组做区分 cell.buttonTwo.tag = indexPath.item + firstData.count cell.buttonTwo.addTarget(self, action: #selector(collectionButtonTapped(_:)), for: .touchUpInside) return cell }
3. 实现点击跳转逻辑
点击时根据tag判断按钮所属分组,拿到对应的主题内容,传给闪卡页面:
@objc func collectionButtonTapped(_ sender: UIButton) { let selectedTopic: String if sender.tag < firstData.count { selectedTopic = firstData[sender.tag] } else { let secondGroupIndex = sender.tag - firstData.count selectedTopic = secondData[secondGroupIndex] } // 初始化闪卡页面,传值 let flashCardVC = storyboard?.instantiateViewController(identifier: "FlashCardVC") as! FlashCardViewController flashCardVC.currentTopic = selectedTopic navigationController?.pushViewController(flashCardVC, animated: true) // 如果要保留之前的segue写法,就替换成下面的代码,记得在prepare方法里把selectedTopic传给目标页面 // let segueID = sender.tag < firstData.count ? "showFirstGroupCard" : "showSecondGroupCard" // performSegue(withIdentifier: segueID, sender: selectedTopic) }
4. 闪卡页面接收参数
新建闪卡页面对应的控制器,加一个属性接收传过来的主题,页面加载时根据主题加载对应闪卡内容即可:
class FlashCardViewController: UIViewController { var currentTopic: String = "" override func viewDidLoad() { super.viewDidLoad() navigationItem.title = currentTopic // 在这里根据currentTopic匹配加载对应的闪卡数据 } }
优化建议
- 两个自定义Cell的样式、逻辑完全一致,可以合并成一个通用集合视图Cell,减少冗余代码
- 尽量少用强制解包(
!),比如buttonOne.titleLabel!这类写法,布局未加载完成时会直接触发崩溃,改成可选链或者提前判空更稳妥 - 处理集合视图点击优先用
UICollectionViewDelegate自带的didSelectItemAt代理方法,比给Cell内的按钮单独加事件更符合设计规范,也不会出现事件冲突
内容的提问来源于stack exchange,提问作者Dakota Davis
相关产品推荐
相关产品推荐

