如何在 SwiftUI TextField 中将光标移动到末尾?

njd*_*per 15 swiftui

我正在使用带有绑定字符串的 SwiftUI TextField 将用户的输入更改为电话格式。键入时,格式正在发生,但光标不会移动到文本字段的末尾,它会保留在输入时的位置。例如,如果我输入1,则 texfield 的值(格式化后)将为(1,但光标停留在第一个字符之后,而不是行尾。

有没有办法将文本字段的光标移动到行尾?

这是示例代码:

import SwiftUI
import AnyFormatKit

struct ContentView: View {
    @State var phoneNumber = ""
    let phoneFormatter = DefaultTextFormatter(textPattern: "(###) ###-####")

    var body: some View {

    let phoneNumberProxy = Binding<String>(
        get: {
            return (self.phoneFormatter.format(self.phoneNumber) ?? "")
        },
        set: {
            self.phoneNumber = self.phoneFormatter.unformat($0) ?? ""
        }
    )

        return TextField("Phone Number", text: phoneNumberProxy)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 8

您可能必须使用UITextField代替TextField. UITextField允许设置自定义光标位置。将光标定位在文本的末尾,您可以使用它textField.endOfDocument来设置UITextField.selectedTextRange文本内容的更新时间。

@objc func textFieldDidChange(_ textField: UITextField) {        
    let newPosition = textField.endOfDocument
    textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}
Run Code Online (Sandbox Code Playgroud)

以下 SwiftUI 代码片段显示了一个示例实现。

import SwiftUI
import UIKit
//import AnyFormatKit

struct ContentView: View {
    @State var phoneNumber = ""

    let phoneFormatter = DefaultTextFormatter(textPattern: "(###) ###-####")

    var body: some View {

    let phoneNumberProxy = Binding<String>(
        get: {
            return (self.phoneFormatter.format(self.phoneNumber) ?? "")
        },
        set: {
            self.phoneNumber = self.phoneFormatter.unformat($0) ?? ""
        }
    )

        return TextFieldContainer("Phone Number", text: phoneNumberProxy)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

/************************************************/

struct TextFieldContainer: UIViewRepresentable {
    private var placeholder : String
    private var text : Binding<String>

    init(_ placeholder:String, text:Binding<String>) {
        self.placeholder = placeholder
        self.text = text
    }

    func makeCoordinator() -> TextFieldContainer.Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: UIViewRepresentableContext<TextFieldContainer>) -> UITextField {

        let innertTextField = UITextField(frame: .zero)
        innertTextField.placeholder = placeholder
        innertTextField.text = text.wrappedValue
        innertTextField.delegate = context.coordinator

        context.coordinator.setup(innertTextField)

        return innertTextField
    }

    func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<TextFieldContainer>) {
        uiView.text = self.text.wrappedValue
    }

    class Coordinator: NSObject, UITextFieldDelegate {
        var parent: TextFieldContainer

        init(_ textFieldContainer: TextFieldContainer) {
            self.parent = textFieldContainer
        }

        func setup(_ textField:UITextField) {
            textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
        }

        @objc func textFieldDidChange(_ textField: UITextField) {
            self.parent.text.wrappedValue = textField.text ?? ""

            let newPosition = textField.endOfDocument
            textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)