UITextView长文本打字机效果卡顿延迟问题求助
解决UITextView长文本打字机效果卡顿、不同步问题
问题根源
常见的逐字符延迟方案(比如用DispatchQueue.asyncAfter逐个添加字符)存在两个核心问题:
- 调度延迟累积:每个字符的延迟基于初始时间计算,但系统调度任务时的微小延迟会在长文本下不断累积,导致动画越来越慢、不同步。
- 频繁重绘开销:每次仅更新一个字符,会触发UITextView频繁重绘,长文本下主线程负载过高,引发卡顿。
优化方案:用CADisplayLink实现同步流畅的打字机效果
CADisplayLink与屏幕刷新率同步,每帧更新一次内容,既避免了调度延迟累积,又能通过控制每帧更新的字符数减少重绘次数。
完整TypewriterTextView实现
import UIKit class TypewriterTextView: UITextView { private var displayLink: CADisplayLink? private var fullText: String = "" private var currentIndex: Int = 0 // 每帧显示的字符数,可根据需求调整 private var charsPerFrame: Int = 1 // 单个字符的间隔时间(秒),与charsPerFrame配合控制整体速度 private var typingSpeed: TimeInterval = 0.05 func startTyping(with text: String) { fullText = text currentIndex = 0 text = "" // 终止之前的动画 displayLink?.invalidate() // 根据屏幕刷新率计算每帧应显示的字符数 let framesPerSecond = 60.0 charsPerFrame = Int(framesPerSecond * typingSpeed) charsPerFrame = max(charsPerFrame, 1) displayLink = CADisplayLink(target: self, selector: #selector(updateText)) displayLink?.add(to: .main, forMode: .common) } func stopTyping() { displayLink?.invalidate() displayLink = nil text = fullText } @objc private func updateText() { guard currentIndex < fullText.count else { stopTyping() return } // 计算当前帧要显示的文本范围 let endIndex = min(currentIndex + charsPerFrame, fullText.count) let substring = fullText[fullText.startIndex..<fullText.index(fullText.startIndex, offsetBy: endIndex)] text = String(substring) // 自动滚动到文本末尾,保持内容可视 let range = NSRange(location: text.count, length: 0) scrollRangeToVisible(range) currentIndex = endIndex } deinit { displayLink?.invalidate() } }
测试调用代码
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let typewriterView = TypewriterTextView(frame: CGRect(x: 20, y: 100, width: view.bounds.width - 40, height: 300)) typewriterView.font = .systemFont(ofSize: 16) typewriterView.backgroundColor = .lightGray view.addSubview(typewriterView) // 替换为你的长文本内容 let longTestText = "这里可以放入任意长度的测试文本,无论是几百字还是几千字,这个方案都能保持流畅的打字机效果,不会出现卡顿或不同步的问题。你可以调整typingSpeed和charsPerFrame参数来控制打字速度,满足不同场景的需求。" typewriterView.startTyping(with: longTestText) } }
方案优势
- 同步流畅:CADisplayLink绑定屏幕刷新率,动画与UI刷新完全同步,不会出现累积延迟。
- 低开销:每帧可更新多个字符,大幅减少UITextView的重绘次数,长文本下主线程压力更小。
- 可定制性:通过
typingSpeed和charsPerFrame可以灵活调整打字速度,适配不同需求。
内容的提问来源于stack exchange,提问作者impo
相关产品推荐
相关产品推荐

