iOS开发:实现TextView达第7行时自动滚动至顶部并追加内容
实现iOS TextView实时滚动并自动截断旧内容(保持指定行数显示)
嗨,我明白你想要实现的是语音识别实时文本显示的滚动效果——当内容到第7行末尾时,旧内容自动被顶掉,最新的内容始终留在可视区域,对吧?我之前也做过类似的需求,给你几个可行的解决方案:
方案一:自定义TextView内容处理,实时截断超出行数的旧内容
这个方案直接基于你现有的TextView,核心思路是每次追加文本后,检查当前行数是否超过7,超过就自动截断最前面的内容,只保留最后7行,同时确保滚动到最新内容位置。
1. 先实现一个计算TextView行数的工具方法
func getTextViewLineCount(_ textView: UITextView) -> Int { guard let layoutManager = textView.layoutManager, let textContainer = textView.textContainer else { return 0 } let glyphRange = layoutManager.glyphRange(for: textContainer) let lineRects = layoutManager.lineFragmentRects(forGlyphRange: glyphRange, withoutAdditionalLayout: true) return lineRects.count }
2. 在追加语音文本的逻辑中加入截断处理
假设你有一个接收语音识别结果的方法,在里面做如下处理:
func appendRecognizedText(_ text: String) { // 追加新文本 textView.text.append(text) // 检查当前行数是否超过7 let currentLineCount = getTextViewLineCount(textView) if currentLineCount > 7 { guard let layoutManager = textView.layoutManager, let textContainer = textView.textContainer else { return } // 获取最后7行的起始字符位置 let glyphRange = layoutManager.glyphRange(for: textContainer) let lineRects = layoutManager.lineFragmentRects(forGlyphRange: glyphRange, withoutAdditionalLayout: true) let startGlyphIndex = layoutManager.glyphIndex(for: lineRects[lineRects.count - 7].origin) let stringRange = layoutManager.characterRange(forGlyphRange: NSRange(location: startGlyphIndex, length: glyphRange.length - startGlyphIndex), actualGlyphRange: nil) // 截断文本,只保留最后7行 if let newText = textView.text?.substring(with: stringRange) { textView.text = newText } } // 滚动到内容底部,确保最新文本可见 let bottomOffset = CGPoint(x: 0, y: textView.contentSize.height - textView.bounds.size.height) textView.setContentOffset(bottomOffset, animated: false) }
方案二:用UITableView实现更灵活的内容控制
如果你觉得TextView的行数计算有点麻烦,用UITableView会更直观——只需要维护一个数据源数组,每次新增文本时,控制数组最多保留7条(或者1条,满足你“只显示最后一行”的需求),然后刷新表格并滚动到最后一行。
1. 准备数据源和基础配置
// 存储语音识别文本的数据源 var recognizedTexts: [String] = [] // 表格单元格复用标识符 let speechCellIdentifier = "SpeechTextCell" // 在viewDidLoad里注册单元格 override func viewDidLoad() { super.viewDidLoad() tableView.register(UITableViewCell.self, forCellReuseIdentifier: speechCellIdentifier) tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 44 }
2. 追加文本并控制数据源
func appendRecognizedText(_ text: String) { recognizedTexts.append(text) // 超过7条就移除最旧的第一条 if recognizedTexts.count > 7 { recognizedTexts.removeFirst() } // 如果只想显示最后一行,把上面的判断改成`if recognizedTexts.count > 1`即可 tableView.reloadData() // 滚动到最后一行,确保最新内容可见 if recognizedTexts.count > 0 { let lastIndexPath = IndexPath(row: recognizedTexts.count - 1, section: 0) tableView.scrollToRow(at: lastIndexPath, at: .bottom, animated: false) } }
3. 实现UITableView的代理方法
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return recognizedTexts.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: speechCellIdentifier, for: indexPath) cell.textLabel?.text = recognizedTexts[indexPath.row] cell.textLabel?.numberOfLines = 0 // 允许文本换行 return cell }
小提示
在实时语音识别的场景中,尽量避免过于频繁的文本更新(比如每识别一个字就更新一次),可以攒一小段文本再处理,这样能减少性能消耗,让滚动更流畅~
内容的提问来源于stack exchange,提问作者Chaitali
相关产品推荐
相关产品推荐

