如何优化UITextView以消除首次滚动卡顿问题?
解决UITextView首次滚动卡顿的方案
针对你遇到的首次滚动卡顿问题,核心原因是主线程同步创建大量富文本+滚动时才触发文本布局计算,可以通过以下几个方向优化:
1. 后台线程创建富文本,主线程赋值
把富文本的构建逻辑放到后台队列,避免阻塞主线程:
override func viewDidLoad() { super.viewDidLoad() Track(id: track!.id).getLyrics { [weak self] response in guard let self = self, let text = response?.lyrics_text else { return } var writtenBy = response?.lyrics_writers ?? "" if writtenBy.isEmpty { writtenBy = self.track?.album?.artistsString() ?? "" } // 后台线程处理富文本 DispatchQueue.global(qos: .userInitiated).async { let style = NSMutableParagraphStyle() style.lineSpacing = 10 let attributes = [ NSAttributedString.Key.font: UIFont(name: "Helvetica", size: 19)!, NSAttributedString.Key.foregroundColor: UIColor(named: "Primary Material")!, NSAttributedString.Key.paragraphStyle: style ] let fullText = self.writtenByPhrase + " " + writtenBy + "\n\n" + text let attributedText = NSMutableAttributedString(string: fullText, attributes: attributes) attributedText.addAttribute(.font, value: UIFont(name: "Helvetica-Bold", size: 19)!, range: NSRange(location: 0, length: self.writtenByPhrase.count)) // 主线程更新UI DispatchQueue.main.async { self.textView?.attributedText = attributedText self.textView?.scrollRangeToVisible(NSRange(location: 0, length: 0)) // 提前触发布局计算 self.triggerTextViewLayout() } } } // 提前配置文本容器,减少回调内操作 textView?.textContainer.lineFragmentPadding = 20 textView?.textContainerInset = UIEdgeInsets(top: 20, left: 0, bottom: 200, right: 0) } // 主动触发文本布局,避免滚动时才计算 private func triggerTextViewLayout() { guard let textView = textView else { return } textView.layoutManager.ensureLayout(for: textView.textContainer) textView.setNeedsLayout() textView.layoutIfNeeded() }
2. 提前缓存字体
UIFont(name:...)首次调用会加载字体文件,可能产生IO延迟。建议在App启动阶段提前缓存所需字体:
// 在AppDelegate或全局初始化类中缓存 let cachedHelvetica = UIFont(name: "Helvetica", size: 19)! let cachedHelveticaBold = UIFont(name: "Helvetica-Bold", size: 19)! // 后续直接使用缓存的字体 let attributes = [ NSAttributedString.Key.font: cachedHelvetica, // ...其他属性 ]
3. 开启异步绘制优化
对于超长文本,可开启异步绘制减少主线程压力:
// 在viewDidLoad中设置 textView?.layer.drawsAsynchronously = true textView?.layoutManager.allowsNonContiguousLayout = true // 默认已开启,明确设置更稳妥
关键优化逻辑
- 富文本创建属于CPU密集型操作,后台处理避免阻塞主线程;
- 主动触发
ensureLayout让布局管理器提前计算文本排版,滚动时直接复用结果; - 字体缓存消除首次加载字体的IO开销;
内容的提问来源于stack exchange,提问作者Perzifale
相关产品推荐
相关产品推荐

