Swift 4.1自定义TableViewCell复用时代理视图重复显示问题
解决Swift 4.1中TableViewCell复用导致CGRect重复显示的问题
嘿,这个问题我太熟悉了——UITableView的单元格复用机制就是罪魁祸首!当cell被滚出可视区域后,会被放进复用池,下次再被取出来时,你之前在addBlock里绘制的CGRect并没有被清除,所以新的数据来了之后,旧的绘制内容还留在上面,就出现了重复显示的情况。
下面给你两种最常用的解决思路,结合你的代码场景来调整:
方法一:在添加新内容前清除旧的绘制残留
如果你是通过添加子视图(比如用UIView模拟CGRect)实现的绘制,建议专门用一个容器视图管理所有绘制元素,方便批量清除:
class CustomTableViewCell: UITableViewCell { // 专门存放CGRect视图的容器,方便统一清除 private let blockContainer = UIView() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) contentView.addSubview(blockContainer) // 设置容器约束,适配你的cell布局 blockContainer.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ blockContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), blockContainer.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), blockContainer.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), blockContainer.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8) ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func addBlock(item: YourItemModel) { // 第一步:清除容器内所有旧的CGRect视图 blockContainer.subviews.forEach { $0.removeFromSuperview() } // 第二步:根据当前item重新创建并添加新的CGRect视图 let blockFrame = CGRect(x: 0, y: 0, width: item.blockWidth, height: item.blockHeight) let newBlockView = UIView(frame: blockFrame) newBlockView.backgroundColor = UIColor.systemBlue // 替换成你的样式 blockContainer.addSubview(newBlockView) } }
如果你的CGRect是通过重写draw(_ rect:)直接绘制的,要在绘制前先清除上下文:
override func draw(_ rect: CGRect) { super.draw(rect) guard let context = UIGraphicsGetCurrentContext() else { return } // 先清除当前cell的绘制上下文 context.clear(rect) // 再根据当前数据绘制新的CGRect let targetRect = CGRect(x: 16, y: 8, width: 100, height: 40) UIColor.systemRed.setFill() UIBezierPath(rect: targetRect).fill() }
方法二:利用prepareForReuse方法重置cell状态
UITableView在复用cell前会自动调用prepareForReuse,你可以在这里统一重置cell状态,清除旧绘制内容:
class CustomTableViewCell: UITableViewCell { private let blockContainer = UIView() // ... 其他初始化代码 ... override func prepareForReuse() { super.prepareForReuse() // 清除旧的CGRect视图 blockContainer.subviews.forEach { $0.removeFromSuperview() } // 如果是draw方式,触发重绘 self.setNeedsDisplay() } func addBlock(item: YourItemModel) { // 直接添加新内容即可,旧内容已经在prepareForReuse里清除了 let blockFrame = CGRect(x: 0, y: 0, width: item.blockWidth, height: item.blockHeight) let newBlockView = UIView(frame: blockFrame) newBlockView.backgroundColor = UIColor.systemBlue blockContainer.addSubview(newBlockView) } }
核心思路总结
不管用哪种方法,核心都是在cell复用前彻底清除之前的绘制残留,保证每次复用cell时,都是从干净的状态开始渲染当前行的数据。
内容的提问来源于stack exchange,提问作者Luke Lee
相关产品推荐
相关产品推荐

