UICollectionView多次reload后单元格尺寸异常问题求助
UICollectionView 单元格尺寸二次加载异常问题修复
看起来你遇到的问题很典型,核心原因出在字典遍历的无序性上,我来帮你拆解并解决:
问题分析
你当前在sizeForItemAt方法里通过遍历mainCategoryDic字典来匹配indexPath.row,但Swift的Dictionary是无序集合——首次加载时遍历顺序可能刚好和你预期的一致,但重新加载时字典的内部遍历顺序可能发生变化,导致你取到的不是对应位置的字符串,计算出的尺寸自然就混乱了。
先看你当前的代码:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { var i:Int = 0 var size = CGSize() for t in mainCategoryDic { if(i == indexPath.row) { let index:String = t.key size = (mainCategoryDic[index]?.name?.size(withAttributes: [NSAttributedString.Key.font : UIFont(name:font_name, size: 14)!]))! } i += 1 } return CGSize(width: size.width + 38.0, height: 30.0) }
修复方案
解决思路很简单:把无序的字典转换成有序数组,后续所有数据读取(包括尺寸计算和单元格内容填充)都基于这个有序数组,保证每次加载的顺序完全一致。
步骤1:提前将字典转换为有序数组
在数据初始化或更新时,把字典转成有序数组(可以按业务需求排序,比如按key、名称等):
// 假设你的数据模型是Category,先定义一个有序数组存储数据 var mainCategoryArray: [(key: String, value: Category)] = [] // 在获取到mainCategoryDic后,转换成有序数组(这里示例按key升序排序) mainCategoryArray = mainCategoryDic.sorted { $0.key < $1.key } // 如果需要按名称排序,可替换为: // mainCategoryArray = mainCategoryDic.sorted { $0.value.name ?? "" < $1.value.name ?? "" }
步骤2:修改sizeForItemAt方法
直接从有序数组中取对应位置的数据,同时处理可选值避免崩溃:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // 安全获取数据和字体 guard let category = mainCategoryArray[indexPath.row].value, let name = category.name, let font = UIFont(name: font_name, size: 14) else { // 兜底返回默认尺寸,防止崩溃 return CGSize(width: 80, height: 30) } // 计算文本尺寸 let textSize = name.size(withAttributes: [.font: font]) return CGSize(width: textSize.width + 38.0, height: 30.0) }
额外优化建议
- 缓存尺寸:如果数据不会频繁变化,可以提前计算好所有单元格的尺寸并存入数组,避免每次
sizeForItemAt都重复计算字符串尺寸,提升滚动性能。 - 统一数据源:后续单元格内容填充(
cellForItemAt)也建议使用这个有序数组,保证数据和尺寸的对应关系完全一致。
内容的提问来源于stack exchange,提问作者ZahraAsgharzade
相关产品推荐
相关产品推荐

