CAShapeLayer无法正常移除,UICollectionView滑动后cell出现图层残留如何解决?
问题根因
- UICollectionView采用单元格复用机制,你每次在
cellForItemAt方法中调用addView接口时,都会生成一个全新的subView添加到cell.takeProgressView上,但你仅在addView中清除了当前TakeProgressView实例持有的图层,复用单元格上之前添加的旧子视图、旧图层完全没有被移除,多次滑动后同一个单元格上会叠加多层半透明进度层,就会出现你观察到的淡色残留痕迹。 - 你每次调用
cellForItemAt都会新建一个TakeProgressView实例,旧实例生成的子视图和图层不属于新实例,你在新实例addView方法中执行的agreeLayer.removeFromSuperlayer()这类操作,完全无法清除旧单元格上已经存在的视图和图层,操作无效。
修复方案
方案1:添加新视图前先清空目标容器的旧内容
修改addView方法,在添加新的subView之前,先把传入的目标容器view上的所有旧子视图全部移除:
func addView(view: UIView, withParticipants: Bool){ // 新增这行代码:先清空目标容器上的所有旧子视图 view.subviews.forEach { $0.removeFromSuperview() } // 原有逻辑保持不变 disagreePath.removeAllPoints() agreePath.removeAllPoints() path.removeAllPoints() circlePath.removeAllPoints() agreeLayer.removeFromSuperlayer() disagreeLayer.removeFromSuperlayer() backgroundFill.removeFromSuperlayer() // ... 剩下的原有代码 }
方案2:优化单元格复用逻辑(更推荐)
把进度服务实例放到单元格内部作为属性,避免每次复用都重复创建实例,性能更优:
- 在
TakeCollectionViewCell中新增属性,提前初始化进度服务:
class TakeCollectionViewCell: UICollectionViewCell { // 原有其他属性、IBOutlet保持不变 @IBOutlet weak var takeProgressView: UIView! let progressService = TakeProgressView() }
- 重写单元格的复用准备方法,在复用时提前清空旧内容:
override func prepareForReuse() { super.prepareForReuse() takeProgressView.subviews.forEach { $0.removeFromSuperview() } }
- 修改
cellForItemAt逻辑,复用单元格内部的进度服务实例:
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath) as? TakeCollectionViewCell else {return UICollectionViewCell()} let random = Double(indexPath.row) / 10 cell.progressService.progress = random cell.progressService.addView(view: cell.takeProgressView, withParticipants: false) return cell
内容的提问来源于stack exchange,提问作者Noah Iarrobino
相关产品推荐
相关产品推荐

