iOS 15及以下版本CollectionView选中单元格背景色兼容问题
UICollectionView 单元格选中状态颜色全版本适配方案
问题背景
需求为UICollectionView单元格选中时,切换背景视图、文本标签、按钮色调的颜色。现有代码在iOS 15以下版本使用didSet能正常生效,但改为willSet仅在iOS 15上有效,无法兼容低版本,需要一套兼容iOS 15及以下的解决方案。
优化后解决方案
1. 修复单元格isSelected重写逻辑
重写单元格的isSelected属性,通过didSet触发UI更新,同时可额外处理isHighlighted实现选中过渡效果,确保全版本兼容:
class CustomCollectionCell: UICollectionViewCell { // 假设已声明以下控件 @IBOutlet weak var lblName: UILabel! @IBOutlet weak var cellBGView: UIView! @IBOutlet weak var cellInfoBtn: UIButton! override var isSelected: Bool { didSet { updateUIForSelectionState() } } // 可选:处理高亮状态,优化交互体验 override var isHighlighted: Bool { didSet { updateUIForSelectionState(isHighlighted: isHighlighted) } } /// 根据选中/高亮状态更新UI private func updateUIForSelectionState(isHighlighted: Bool = false) { // 高亮状态优先级高于选中状态,可根据需求调整 let shouldShowSelectedStyle = isHighlighted || isSelected lblName.textColor = shouldShowSelectedStyle ? .white : .themeColor cellBGView.backgroundColor = shouldShowSelectedStyle ? .themeColor : .white cellInfoBtn.tintColor = shouldShowSelectedStyle ? .white : .themeColor } }
2. 优化UICollectionView代理逻辑
避免通过reloadData()刷新整个列表,直接利用UICollectionView的选中状态管理API,提升性能同时保证状态正确:
// 控制器中保存选中的IndexPath private var selectedIndexPath: IndexPath? func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 取消之前选中的单元格 if let oldSelectedIndex = selectedIndexPath { collectionView.deselectItem(at: oldSelectedIndex, animated: true) } // 更新当前选中记录 selectedIndexPath = indexPath } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionCell", for: indexPath) as! CustomCollectionCell cell.cellInfoBtn.tag = indexPath.row cell.cellInfoBtn.addTarget(self, action: #selector(infoBtnTapped(_:)), for: .touchUpInside) // 页面初始化时如需默认选中某行,可添加以下代码 // cell.isSelected = (selectedIndexPath == indexPath) return cell }
问题根源说明
- 错误的super调用:原代码中在
didSet内手动设置super.isSelected = true/false是多余的,重写isSelected时系统会自动处理父类属性,手动赋值会导致状态混乱。 - 低效的刷新方式:调用
collectionView.reloadData()会触发所有单元格的复用重建,不仅性能差,还可能干扰系统对选中状态的管理。 - 版本行为差异:iOS 15后
willSet的触发时机与低版本不同,而didSet在所有iOS版本中都会在属性值真正变更后触发,是更可靠的UI更新时机。
内容的提问来源于stack exchange,提问作者subbu M
相关产品推荐
相关产品推荐

