UICollectionView Cell滚动后评分图标消失,如何持久显示?
UICollectionView滚动后评分图标消失的解决方案
问题原因
核心问题是UICollectionView的Cell复用机制:当Cell滚出屏幕后会被回收复用,你当前仅在Cell内部保存评分状态,未将状态同步到数据源模型中;同时prepareForReuse方法清空了btnRate.image,导致复用Cell时无法恢复之前的评分状态。
解决步骤
- 给数据源模型添加评分状态属性:将评分结果存储在数据源(
Responder)中,而非仅保存在Cell内部 - 在Cell的
configure方法中恢复评分状态:每次Cell被复用配置时,根据模型的评分状态显示对应图标 - 修改评分按钮逻辑:点击评分按钮时,更新对应数据源模型的评分状态,确保状态持久化
修改后的代码示例
1. 扩展数据源模型,添加评分状态
// 定义评分类型枚举 enum RatingType: String { case none, good, hate } // 修改Responder模型,新增评分状态属性 class Responder { var id: String? var packShot: PackShot? // 保留原有属性 var ratingType: RatingType = .none // 新增评分状态字段 }
2. 修改ViewController代码
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reUseMoviesCellID, for: indexPath) as! MoviesCollectionCell let currentMovie = movieObj[indexPath.row] // 绑定按钮ID cell.btnSmallGoodRate.id = currentMovie.id ?? "" cell.btnSmallHateRate.id = currentMovie.id ?? "" // 修改tapHandler,传递评分类型用于更新数据源 cell.tapHandler = { ratingType in Commons.userGlobalRate += 1 self.lblRated.text = "\(Commons.userGlobalRate) rated" self.ratedView.backgroundColor = .ratedGoldColour if Commons.progressBarValue < 1 { Commons.progressBarValue += 0.2 self.ratedTrackBarView.setProgress(Commons.progressBarValue, animated: true) } // 更新数据源的评分状态 currentMovie.ratingType = ratingType } // 配置Cell,包含评分状态恢复 cell.configure(with: currentMovie) return cell }
3. 修改MoviesCollectionCell代码
class MoviesCollectionCell: UICollectionViewCell { // 修改tapHandler为带参数类型,传递评分类型 var tapHandler: ((RatingType)->())? // 保留原有UI组件定义... override func prepareForReuse() { super.prepareForReuse() movieImage.image = nil // 重置评分相关UI状态 btnRate.alpha = 0 btnRate.image = nil movieOverlay.alpha = 0 btnSmallGoodRate.alpha = 0 btnSmallHateRate.alpha = 0 removeOverlay.alpha = 0 } func configure(with res: Responder){ movieImage.sd_setImage(with: URL(string: res.packShot?.thumbnail ?? ""), placeholderImage: UIImage(named: "ImagePlaceholder")) // 根据模型的评分状态恢复UI switch res.ratingType { case .good: btnRate.alpha = 1 btnRate.image = UIImage(named: "goodRate") case .hate: btnRate.alpha = 1 btnRate.image = UIImage(named: "HateIt") case .none: btnRate.alpha = 0 btnRate.image = nil } } // 保留原有的长按、关闭方法... @objc func hateItem(_ sender: UIButton){ guard let gestureVariable = sender as? ButtonRating else{ return } let movieID = gestureVariable.id print("Hate movie ID ", movieID) // 隐藏评分按钮面板 btnSmallHateRate.alpha = 0 btnSmallGoodRate.alpha = 0 removeOverlay.alpha = 0 // 设置当前Cell的评分UI btnRate.alpha = 1 btnRate.image = UIImage(named: "HateIt") // 通知VC更新数据源 tapHandler?(.hate) } @objc func goodItem(_ sender: UIButton){ guard let gestureVariable = sender as? ButtonRating else{ return } let movieID = gestureVariable.id print("Good movie ID ", movieID) // 隐藏评分按钮面板 btnSmallHateRate.alpha = 0 btnSmallGoodRate.alpha = 0 removeOverlay.alpha = 0 // 设置当前Cell的评分UI btnRate.alpha = 1 btnRate.image = UIImage(named: "goodRate") // 通知VC更新数据源 tapHandler?(.good) } // 保留其他原有代码... }
关键说明
- 所有状态必须保存在数据源模型中,Cell仅负责根据模型渲染UI,避免复用导致状态丢失
configure方法是Cell的唯一配置入口,所有UI状态都要在这里根据模型设置prepareForReuse负责重置Cell的初始状态,避免旧状态干扰新数据的展示
内容的提问来源于stack exchange,提问作者KwameB
相关产品推荐
相关产品推荐

