嵌套CollectionView遇问题:取巧方案效果不佳求优化
嵌套UICollectionView的正确实现方式
核心思路
让每个外层CollectionViewCell独立管理自身的内层CollectionView,将配置逻辑放在cell的生命周期初始化阶段,通过数据传递实现动态内容展示,同时处理cell复用的状态重置问题,避免重复设置delegate/dataSource导致的异常。
修改后的代码实现
外层ViewController代码
class ViewController3: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { @IBOutlet weak var outCollection: UICollectionView! // 模拟外层数据源,每个元素对应一个内层CollectionView的展示数据 private let outerData: [[String]] = [ ["1-1", "1-2", "1-3", "1-4"], ["2-1", "2-2"], ["3-1", "3-2", "3-3"], ["4-1"], ["5-1", "5-2", "5-3", "5-4", "5-5"] ] override func viewDidLoad() { super.viewDidLoad() outCollection.dataSource = self outCollection.delegate = self // 若使用代码注册外层cell,取消下方注释 // outCollection.register(CollectionViewCell.self, forCellWithReuseIdentifier: "outCell") } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return outerData.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "outCell", for: indexPath) as! CollectionViewCell cell.backgroundColor = .green // 给外层cell传递对应内层数据源 cell.configure(with: outerData[indexPath.item]) return cell } }
内层CollectionViewCell代码
class CollectionViewCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDataSource { @IBOutlet weak var inCollection: UICollectionView! // 存储内层CollectionView的数据源 private var innerData: [String] = [] override init(frame: CGRect) { super.init(frame: frame) setupInnerCollection() } required init?(coder: NSCoder) { super.init(coder: coder) setupInnerCollection() } // 初始化内层CollectionView的基础配置(仅执行一次) private func setupInnerCollection() { // 若使用代码注册内层cell,取消下方注释 // inCollection.register(innercellulosa.self, forCellWithReuseIdentifier: "inCell") // 设置内层CollectionView的布局(示例为横向流式布局) let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal layout.itemSize = CGSize(width: 80, height: 80) inCollection.collectionViewLayout = layout // 一次性设置delegate和dataSource为cell自身 inCollection.delegate = self inCollection.dataSource = self } // 对外暴露的配置方法,接收外层传递的数据源并刷新 func configure(with data: [String]) { innerData = data inCollection.reloadData() } // 处理cell复用,重置内层数据与状态 override func prepareForReuse() { super.prepareForReuse() innerData = [] inCollection.reloadData() } // MARK: - UICollectionView 数据源与代理方法 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return innerData.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "inCell", for: indexPath) as! innercellulosa cell.backgroundColor = .red // 若需设置内层cell内容,可在此处操作 // cell.textLabel?.text = innerData[indexPath.item] return cell } }
常见问题解决说明
- 直接设置内层CollectionView代理出错的原因:内层CollectionView属于可复用的外层cell,若在ViewController或非cell初始化阶段设置代理,会因cell复用导致代理关联混乱,回调逻辑出错。
- 关键优化点:
- 内层CollectionView的配置(代理、布局、cell注册)仅在cell初始化时执行一次,避免重复操作
- 通过
configure(with:)方法传递数据,保证每个外层cell对应的内层内容准确 - 实现
prepareForReuse方法重置状态,彻底避免复用导致的旧数据残留 - 由cell自身承担内层CollectionView的代理与数据源逻辑,代码内聚性更强,维护更方便
内容的提问来源于stack exchange,提问作者Noob lvl 1
相关产品推荐
相关产品推荐

