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

如何检测TextField/TextEditor中用户换行并自动添加列表符号?

实现TextEditor回车自动添加列表符号

要实现这个效果,SwiftUI原生的TextEditor自带回调搞不定,得用它底层的UITextView来做核心处理:

  1. 自定义一个包装UITextView的View,实现UIViewRepresentable协议
  2. 在UITextViewDelegate的textView(_:shouldChangeTextIn:replacementText:)方法里检测换行符
  3. 当用户按下回车时,自动在新行开头插入-

以下是完整代码示例:

import SwiftUI

struct ListTextEditor: UIViewRepresentable {
    @Binding var text: String
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.delegate = context.coordinator
        textView.font = UIFont.systemFont(ofSize: 16)
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        if uiView.text != text {
            uiView.text = text
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: ListTextEditor
        
        init(_ parent: ListTextEditor) {
            self.parent = parent
        }
        
        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            // 检测是否是换行按键
            if text == "\n" {
                let currentText = textView.text ?? ""
                let startIndex = currentText.index(currentText.startIndex, offsetBy: range.location)
                let beforeText = currentText[..<startIndex]
                
                // 判断当前是否处于新行开头
                if beforeText.isEmpty || beforeText.last == "\n" {
                    // 插入换行+列表符号
                    let newText = currentText.replacingCharacters(in: range, with: "\n- ")
                    parent.text = newText
                    // 把光标移到列表符号后面,保证输入流畅
                    let newCursorPosition = NSRange(location: range.location + 3, length: 0)
                    textView.selectedRange = newCursorPosition
                    return false // 自己处理文本替换,跳过系统默认操作
                }
            }
            // 其他按键操作正常处理,同步更新绑定文本
            let newText = (textView.text ?? "").replacingCharacters(in: range, with: text)
            parent.text = newText
            return true
        }
    }
}

// 使用示例
struct ContentView: View {
    @State private var editorText = "- "
    
    var body: some View {
        ListTextEditor(text: $editorText)
            .padding()
            .frame(minHeight: 300)
            .border(Color.gray.opacity(0.3))
    }
}

关键细节说明:

  • 用UIViewRepresentable封装UITextView,才能拿到底层的代理回调来监听按键事件
  • 拦截换行符后,判断当前是否是新行开头,避免在一行中间换行时错误添加列表符号
  • 手动调整光标位置到- 后面,让用户可以直接继续输入内容,体验更顺畅
  • 初始文本设为- ,可以让用户打开编辑器就处于列表输入状态

这样用户每次按下回车,新行都会自动带上- ,和Word的自动列表效果完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:28:10