Swift中UICollectionReusableView子类代理回调:多Section下获取点击位置
解决UICollectionView自定义页眉/页脚PageControl点击的Section定位问题
针对多个section使用带PageControl的自定义页眉/页脚时,无法直接通过视图获取对应IndexPath的问题,这里提供两种可靠的解决思路:
方案一:存储IndexPath + 闭包回调
这是最直观且不易出错的方式,直接在自定义视图中保存对应的IndexPath,点击时通过闭包传递出去。
1. 修改自定义页眉/页脚类
class CustomCollectionReusableView: UICollectionReusableView { var pageControl: UIPageControl! // 存储当前视图对应的IndexPath var indexPath: IndexPath? // 定义回调闭包,传递IndexPath和选中的页码 var onPageControlTap: ((IndexPath, Int) -> Void)? override init(frame: CGRect) { super.init(frame: frame) setupPageControl() } required init?(coder: NSCoder) { super.init(coder: coder) setupPageControl() } private func setupPageControl() { pageControl = UIPageControl() // 绑定点击事件 pageControl.addTarget(self, action: #selector(pageControlTapped(_:)), for: .valueChanged) addSubview(pageControl) // 这里添加PageControl的布局代码... } @objc private func pageControlTapped(_ sender: UIPageControl) { guard let indexPath = indexPath else { return } // 触发回调 onPageControlTap?(indexPath, sender.currentPage) } }
2. 在数据源方法中配置回调
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if kind == customKind { let reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "CustomCollectionReusableView", for: indexPath) as! CustomCollectionReusableView // 每次复用都重新赋值IndexPath reusableView.indexPath = indexPath // 设置闭包处理点击逻辑 reusableView.onPageControlTap = { [weak self] indexPath, selectedPage in // 这里处理你的业务逻辑,比如获取当前section print("点击了Section \(indexPath.section)的PageControl,选中页码:\(selectedPage)") // 示例:根据section和页码更新对应内容 self?.updateContent(forSection: indexPath.section, page: selectedPage) } // 配置PageControl的总页数(根据当前section的数据设置) reusableView.pageControl.numberOfPages = yourDataArray[indexPath.section].count return reusableView } // 其他类型的补充视图处理 return UICollectionReusableView() }
方案二:自定义代理模式
如果你的项目更倾向于使用协议规范交互,可以用代理模式替代闭包,逻辑和方案一类似,只是回调方式不同。
1. 定义代理协议
protocol CustomCollectionReusableViewDelegate: AnyObject { func reusableView(_ view: CustomCollectionReusableView, didSelectPage page: Int, at indexPath: IndexPath) }
2. 修改自定义视图类
class CustomCollectionReusableView: UICollectionReusableView { var pageControl: UIPageControl! var indexPath: IndexPath? weak var delegate: CustomCollectionReusableViewDelegate? override init(frame: CGRect) { super.init(frame: frame) setupPageControl() } required init?(coder: NSCoder) { super.init(coder: coder) setupPageControl() } private func setupPageControl() { pageControl = UIPageControl() pageControl.addTarget(self, action: #selector(pageControlTapped(_:)), for: .valueChanged) addSubview(pageControl) // 布局代码... } @objc private func pageControlTapped(_ sender: UIPageControl) { guard let indexPath = indexPath else { return } delegate?.reusableView(self, didSelectPage: sender.currentPage, at: indexPath) } }
3. 在ViewController中实现代理
class YourViewController: UIViewController, UICollectionViewDataSource, CustomCollectionReusableViewDelegate { // 其他代码... func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if kind == customKind { let reusableView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "CustomCollectionReusableView", for: indexPath) as! CustomCollectionReusableView reusableView.indexPath = indexPath reusableView.delegate = self reusableView.pageControl.numberOfPages = yourDataArray[indexPath.section].count return reusableView } return UICollectionReusableView() } // 实现代理方法 func reusableView(_ view: CustomCollectionReusableView, didSelectPage page: Int, at indexPath: IndexPath) { print("Section \(indexPath.section)的PageControl选中第\(page)页") // 业务逻辑处理 } }
不推荐的方案:Tag关联Section
虽然可以把PageControl的tag设为当前section的索引,但这种方式存在明显缺陷:如果项目中其他控件也使用tag,容易出现冲突;且当视图复用时,如果忘记更新tag,会导致逻辑错误。因此不推荐在复杂项目中使用。
注意事项
- 无论是闭包还是代理,都要使用
weak self避免循环引用,防止内存泄漏。 - 每次复用自定义视图时,必须重新赋值
indexPath,确保回调的IndexPath是正确的。
内容的提问来源于stack exchange,提问作者Gargo
相关产品推荐
相关产品推荐

