单ViewController中两个UICollectionView的显示问题及报错处理
嘿,我刚处理过几乎一模一样的场景,给你拆解每个问题的解决方案:
问题1:转成UICollectionViewCell后访问自定义属性报错
这个坑我也踩过!原因很简单:你出列的cell被强转成了系统默认的UICollectionViewCell,而这个类根本没有你自定义的titleLabel、imgView属性。解决步骤如下:
先创建自定义Cell子类
新建一个继承自UICollectionViewCell的类,比如CustomCollectionCell,把你的titleLabel和imgView关联到这个类里(不管是代码创建还是xib拖线):class CustomCollectionCell: UICollectionViewCell { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var imgView: UIImageView! // 如果是纯代码创建,就在init方法里添加控件 }注册自定义Cell
在ViewController的viewDidLoad里,给两个CollectionView分别注册自定义Cell(别用系统默认的!):// 用xib注册的方式 collectionView1.register(UINib(nibName: "CustomCollectionCell", bundle: nil), forCellWithReuseIdentifier: "CellID1") collectionView2.register(UINib(nibName: "CustomCollectionCell", bundle: nil), forCellWithReuseIdentifier: "CellID2") // 如果是纯代码创建Cell,就用这个: // collectionView1.register(CustomCollectionCell.self, forCellWithReuseIdentifier: "CellID1")出列时强转成自定义Cell
在cellForItemAt方法里,判断当前是哪个CollectionView,然后把出列的cell强转成你的CustomCollectionCell:func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if collectionView == collectionView1 { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID1", for: indexPath) as! CustomCollectionCell // 这里就能正常访问cell.titleLabel和cell.imgView了 return cell } else { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID2", for: indexPath) as! CustomCollectionCell return cell } }
问题2:为第二个UICollectionView加载对应数据
核心思路是给两个CollectionView分开数据源,不要共用一个数组。步骤如下:
定义两个独立的数据源数组
在ViewController里声明两个数组,分别对应两个CollectionView的数据:// 假设你的数据模型是TipModel,根据实际情况替换 var collection1Data: [TipModel] = [] var collection2Data: [AnotherModel] = [] // 第二个CollectionView的专属数据在数据源方法里区分CollectionView
不管是numberOfItemsInSection还是cellForItemAt,都要先判断当前操作的是哪个CollectionView,再返回对应的数据:// 返回每个CollectionView的item数量 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return collectionView == collectionView1 ? collection1Data.count : collection2Data.count } // 配置每个Cell的内容 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if collectionView == collectionView1 { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID1", for: indexPath) as! CustomCollectionCell let model = collection1Data[indexPath.item] cell.titleLabel.text = model.title cell.imgView.image = UIImage(named: model.imageName) return cell } else { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID2", for: indexPath) as! CustomCollectionCell let model = collection2Data[indexPath.item] cell.titleLabel.text = model.subTitle // 用第二个数据源的字段 cell.imgView.image = UIImage(named: model.iconName) return cell } }别忘了设置Delegate和DataSource
确保两个CollectionView的delegate和dataSource都指向当前ViewController(可以在xib/storyboard里拖线,或者代码设置):override func viewDidLoad() { super.viewDidLoad() collectionView1.delegate = self collectionView1.dataSource = self collectionView2.delegate = self collectionView2.dataSource = self // 加载数据 loadCollection1Data() loadCollection2Data() }
问题3:numberOfItemsInSection固定返回tips.count导致显示异常
这就是问题2里提到的没有区分数据源数量的后果!原来的代码不管是哪个CollectionView,都返回同一个数组的count,导致collectionView2要么显示多余的空cell,要么数据不够显示不全。
解决方法就是把numberOfItemsInSection改成上面问题2里的写法:判断当前是哪个CollectionView,返回对应数据源的count:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { if collectionView == collectionView1 { return collection1Data.count // 第一个CollectionView的数量 } else { return collection2Data.count // 第二个CollectionView的数量 } }
这样collectionView2就会根据自己的数据源数量来显示正确的item个数了。
内容的提问来源于stack exchange,提问作者triff

