iOS15系统下UICollectionView点击卡片无响应、翻转动画异常问题求助
iOS15 UICollectionView 异常行为问题解决方案
问题根因
- 该问题确实由iOS15系统的
UICollectionViewAPI变更导致:iOS15新增了更激进的Cell后台状态同步优化机制,didSelectItemAt回调触发时系统可能正在执行Cell内部状态刷新,此时直接修改Cell子视图属性会被系统的同步逻辑覆盖,所以修改无任何效果。 - 低版本iOS没有该后台同步机制,所以原有代码可正常运行。如果将逻辑移至
cellForItemAt并全局调用reloadData(),会触发所有可见Cell的复用逻辑,iOS15的Cell复用池调度策略和旧版本不同,会优先复用可视区域附近的缓存Cell,导致未点击的Cell也被执行动画代码,出现复用异常。
修复方案
- 首先在卡片数据模型中新增
isFlipped布尔属性,所有卡片的翻转状态统一存储在模型层,从根源避免Cell复用导致的状态错乱。 - 点击事件逻辑全部放在
didSelectItemAt中实现,修改代码如下:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 先更新对应位置的模型状态 cards[indexPath.item].isFlipped.toggle() // 获取当前点击的Cell guard let cell = collectionView.cellForItem(at: indexPath) as? CardCollectionViewCell else { return } // 将视图修改+动画逻辑抛到主队列下一个RunLoop执行,规避系统状态覆盖问题 DispatchQueue.main.async { UIView.transition(with: cell, duration: 0.3, options: .transitionFlipFromRight) { cell.backImageView.isHidden = cell.cardModel.isFlipped cell.frontImageView.isHidden = !cell.cardModel.isFlipped } } }
cellForItemAt中仅做状态赋值,不要加入任何动画逻辑,保证Cell复用时显示正确状态:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CardCell", for: indexPath) as! CardCollectionViewCell let currentCard = cards[indexPath.item] cell.cardModel = currentCard // 直接赋值状态,无动画 cell.backImageView.isHidden = currentCard.isFlipped cell.frontImageView.isHidden = !currentCard.isFlipped return cell }
- 如仍存在异常,可尝试关闭
UICollectionView的预取功能(可选配置):
collectionView.prefetchingEnabled = false
上述方案兼容iOS12及以上全版本系统,不会出现低版本兼容问题。
内容的提问来源于stack exchange,提问作者Fry
相关产品推荐
相关产品推荐

