UITableView滚动卡顿问题求助
兄弟,我之前也踩过这个坑!你现在在tableView(_:cellForRowAt:)里动态创建并添加CodeBlockView,这绝对是UITableView滚动卡顿的元凶——每次cell复用都要重新创建视图、做布局,主线程被这些同步操作占满,滚动的时候自然就掉帧了。给你几个亲测有效的解决思路:
复用CodeBlockView,别每次都新建:别在
cellForRowAt里临时创建CodeBlockView,而是在cell的初始化阶段就把它加到stackView里,默认隐藏。当需要显示代码块时,只更新内容并显示它;不需要时就隐藏。这样能避免重复创建视图带来的性能开销。异步处理代码块的渲染逻辑:如果
CodeBlockView需要做语法高亮、复杂排版这类耗时操作,一定要把这部分逻辑放到后台线程去处理,处理完再切回主线程更新UI。比如用全局队列做代码格式化,再回到主队列设置到视图上,不会阻塞主线程。提前计算并缓存cell高度:动态添加视图很容易让cell高度计算变复杂,系统可能会多次调用
heightForRowAt增加主线程负担。你可以提前计算好每个包含代码块的cell的高度,存在字典里,在heightForRowAt直接返回缓存值,避免实时计算。把布局逻辑移出cellForRow:不要在
cellForRowAt里手动调整视图frame或者调用layoutIfNeeded,这些操作都很耗性能。把布局相关的代码放到cell的layoutSubviews()里,或者用AutoLayout提前设置好约束,让系统自动处理布局。
给你个简单的代码示例参考:
// 自定义ChatCell class ChatCell: UITableViewCell { let contentStackView = UIStackView() let codeBlockView = CodeBlockView() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) // 初始化时就把codeBlockView加入栈视图,默认隐藏 contentStackView.addArrangedSubview(codeBlockView) codeBlockView.isHidden = true contentStackView.axis = .vertical contentView.addSubview(contentStackView) // 设置AutoLayout约束... } func configure(with message: ChatMessage) { // 先处理普通消息内容 if let codeContent = message.codeContent { codeBlockView.isHidden = false // 后台处理代码格式化,避免阻塞主线程 DispatchQueue.global(qos: .userInitiated).async { let formattedCode = self.processCodeHighlight(codeContent) DispatchQueue.main.async { self.codeBlockView.updateContent(with: formattedCode) } } } else { codeBlockView.isHidden = true } } // 模拟代码高亮处理的耗时操作 private func processCodeHighlight(_ code: String) -> NSAttributedString { // 这里可以做语法高亮、字体排版等处理 return NSAttributedString(string: code, attributes: [.font: UIFont.monospacedSystemFont(ofSize: 14, weight: .regular)]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } // cellForRowAt里的调用 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ChatCell", for: indexPath) as! ChatCell let message = messages[indexPath.row] cell.configure(with: message) return cell }
按照这个思路改完,滚动流畅度应该会有明显提升!
内容来源于stack exchange

