You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现按下回车键时在UITableView的textview间切换激活状态

问题原因

  • 仅实现了列表滚动,没有手动切换输入响应者:当前输入焦点仍停留在原来的textView上,所以新输入的内容都会写到第0行的textView中
  • 调用tableView.reloadData()会刷新所有可见cell,打断响应者链,也会导致刚滚动出来的cell被重建,无法正常激活
  • 写死跳转row=1不支持连续跳转,也没有做边界判断

修复方案

第一步:新增获取textView对应行号的便捷方法

private func indexPathForTextView(_ textView: UITextView) -> IndexPath? {
    let point = textView.convert(textView.bounds.origin, to: tableView)
    return tableView.indexPathForRow(at: point)
}

第二步:修改textViewDidChange逻辑

func textViewDidChange(_ textView: UITextView) {
    // 检测换行输入
    guard let newLineRange = textView.text.range(of: "\n") else { return }
    // 移除多余的换行符
    textView.text.removeSubrange(newLineRange)
    
    // 获取当前行、计算下一行,做越界判断
    guard let currentIndex = indexPathForTextView(textView),
          currentIndex.row + 1 < pageCount else { return }
    let nextIndexPath = IndexPath(row: currentIndex.row + 1, section: 0)
    
    // 释放当前textView的输入焦点
    textView.resignFirstResponder()
    
    // 滚动到下一行
    tableView.scrollToRow(at: nextIndexPath, at: .top, animated: true)
    
    // 等待滚动和cell渲染完成后,激活下一行的textView
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { [weak self] in
        guard let self = self,
              let nextCell = self.tableView.cellForRow(at: nextIndexPath) as? EditorTableViewCell else { return }
        nextCell.textView.becomeFirstResponder()
    }
}

注意事项

  • 不要在滚动逻辑中调用reloadData,如果需要持久化每行的文本内容,单独维护一个[String]类型的数组存储每行文本,在cellForRowAt中给cell.textView赋值,在textViewDidChange中同步更新对应索引的数组元素即可
  • 如果追求更丝滑的体验,可以实现UIScrollViewDelegate的scrollViewDidEndScrollingAnimation方法,在滚动结束后再触发下一个textView的激活,不需要硬编码延迟时间
  • 记得在EditorTableViewCell的prepareForReuse方法中清空textView的代理和内容,避免复用导致的异常

内容的提问来源于stack exchange,提问作者NewUser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 23:24:01