如何在一个ViewController中创建多个行为一致的Collection View?
多Collection View复用代码解决方案
核心思路
把通用的Collection View逻辑(数据源、代理、单元格配置)统一处理,通过区分不同Collection View的标识来返回对应分类的数据,避免重复写相同代码。
步骤1:整理数据结构与关联Collection View
首先在ViewController里定义存储不同分类照片的字典,同时关联所有Collection View的IBOutlet:
import UIKit class ClothingViewController: UIViewController { // 关联所有分类的Collection View @IBOutlet weak var topsCollectionView: UICollectionView! @IBOutlet weak var bottomsCollectionView: UICollectionView! @IBOutlet weak var shoesCollectionView: UICollectionView! // 用字典存储不同分类的照片,键为分类名称,值为对应照片数组 var clothingData: [String: [UIImage]] = [ "tops": [], "bottoms": [], "shoes": [] ] override func viewDidLoad() { super.viewDidLoad() // 给所有Collection View统一设置数据源、代理 setupCollectionViews() } // 统一初始化Collection View private func setupCollectionViews() { let collectionViews = [topsCollectionView, bottomsCollectionView, shoesCollectionView] let cellNib = UINib(nibName: "ClothingCell", bundle: nil) for cv in collectionViews { cv?.dataSource = self cv?.delegate = self cv?.register(cellNib, forCellWithReuseIdentifier: "ClothingCell") } } }
步骤2:重构数据源方法,区分不同Collection View
修改UICollectionViewDataSource扩展,通过判断当前Collection View的实例(或tag)返回对应分类的数据:
extension ClothingViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { // 根据Collection View实例匹配对应分类 switch collectionView { case topsCollectionView: return clothingData["tops"]?.count ?? 0 case bottomsCollectionView: return clothingData["bottoms"]?.count ?? 0 case shoesCollectionView: return clothingData["shoes"]?.count ?? 0 default: return 0 } } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ClothingCell", for: indexPath) as! ClothingCell // 获取当前Collection View对应的照片数组 var currentImages: [UIImage] = [] switch collectionView { case topsCollectionView: currentImages = clothingData["tops"] ?? [] case bottomsCollectionView: currentImages = clothingData["bottoms"] ?? [] case shoesCollectionView: currentImages = clothingData["shoes"] ?? [] default: break } // 统一配置单元格 cell.clothingImageView.image = currentImages[indexPath.item] return cell } }
如果觉得用实例判断繁琐,也可以给每个Collection View在Storyboard里设置tag(比如tops设为1,bottoms设为2),然后用tag匹配:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { let category: String switch collectionView.tag { case 1: category = "tops" case 2: category = "bottoms" case 3: category = "shoes" default: category = "" } return clothingData[category]?.count ?? 0 }
步骤3:处理上传与刷新逻辑
当用户选择分类上传照片后,把照片加到对应分类的数组,再刷新对应的Collection View:
// 上传照片时调用的方法,参数为照片和选中的分类 func addClothingImage(_ image: UIImage, toCategory category: String) { // 把照片添加到对应分类的数组 clothingData[category]?.append(image) // 刷新对应的Collection View switch category { case "tops": topsCollectionView.reloadData() case "bottoms": bottomsCollectionView.reloadData() case "shoes": shoesCollectionView.reloadData() default: break } }
常见问题排查
- 之前所有照片只进tops分类:大概率是数据源方法里没有区分Collection View,默认返回了tops的数据,按上面的方式添加判断即可解决。
- 修改数据源报错:检查是否所有Collection View都设置了数据源/代理,是否在Storyboard里正确关联了IBOutlet,或者单元格复用标识符是否一致。
内容的提问来源于stack exchange,提问作者jenna
相关产品推荐
相关产品推荐

