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

SwiftUI中如何在TextField光标当前位置插入字符串?

在SwiftUI的TextField光标位置插入字符串

SwiftUI原生TextField没有直接暴露光标位置的API,要实现光标处插入字符,需要借助UIKit的UITextField封装自定义组件,跟踪光标位置并完成插入逻辑。

步骤1:封装带光标跟踪的自定义TextField

创建UIViewRepresentable组件包装UITextField,对外暴露文本、光标位置的绑定,同时同步文本变化与光标移动状态:

import SwiftUI

struct CursorTextField: UIViewRepresentable {
    @Binding var text: String
    @Binding var selectedRange: NSRange
    var placeholder: String
    
    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.placeholder = placeholder
        textField.delegate = context.coordinator
        textField.addTarget(context.coordinator, action: #selector(Coordinator.textChanged), for: .editingChanged)
        return textField
    }
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        // 避免循环更新:仅当文本不一致时同步
        if uiView.text != text {
            uiView.text = text
        }
        // 同步光标位置
        guard let startPos = uiView.position(from: uiView.beginningOfDocument, offset: selectedRange.location),
              let endPos = uiView.position(from: startPos, offset: selectedRange.length) else { return }
        uiView.selectedTextRange = uiView.textRange(from: startPos, to: endPos)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
        var parent: CursorTextField
        
        init(parent: CursorTextField) {
            self.parent = parent
        }
        
        @objc func textChanged(_ textField: UITextField) {
            parent.text = textField.text ?? ""
            updateCursorRange(textField)
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            updateCursorRange(textField)
        }
        
        private func updateCursorRange(_ textField: UITextField) {
            guard let selectedRange = textField.selectedTextRange else { return }
            let startOffset = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start)
            let length = textField.offset(from: selectedRange.start, to: selectedRange.end)
            parent.selectedRange = NSRange(location: startOffset, length: length)
        }
    }
}

步骤2:主View中实现插入逻辑

用@State变量存储文本和光标位置,按钮点击时根据光标位置插入字符,并更新光标到插入后的位置:

struct ContentView: View {
    @State private var inputText: String = "1234"
    @State private var cursorRange = NSRange(location: 2, length: 0) // 初始光标在"12"和"34"之间
    
    var body: some View {
        VStack {
            CursorTextField(text: $inputText, selectedRange: $cursorRange, placeholder: "Input text")
                .padding()
                .border(.gray)
                .toolbar {
                    ToolbarItemGroup(placement: .keyboard) {
                        Button("+") {
                            insertString(at: cursorRange.location, string: "+")
                        }
                    }
                }
        }
        .padding()
    }
    
    private func insertString(at location: Int, string: String) {
        guard location <= inputText.count else { return }
        
        // 在光标位置插入字符串
        let insertIndex = inputText.index(inputText.startIndex, offsetBy: location)
        inputText.insert(contentsOf: string, at: insertIndex)
        
        // 更新光标到插入字符的后方
        cursorRange = NSRange(location: location + string.count, length: 0)
    }
}

关键说明

  • 自定义CursorTextField会实时同步文本内容和光标位置到SwiftUI状态变量
  • insertString方法负责字符插入与光标位置更新,确保操作后光标停在新字符后方
  • 初始光标位置可根据需求调整,示例中设置的位置点击"+"后会直接得到"12+34"

内容的提问来源于stack exchange,提问作者winner.ktw

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 05:22:21