如何在附加到 TextField 的 swift @Published didSet 中正确格式化字符串?

Posted

技术标签:

【中文标题】如何在附加到 TextField 的 swift @Published didSet 中正确格式化字符串?【英文标题】:how to properly format string in swift @Published didSet attached to the TextField? 【发布时间】:2020-07-21 07:11:38 【问题描述】:

给定一个应该接收电话的TextField,用XX-XX-XXXX模式格式化数字,这个特定的输入字段不允许输入超过8个符号,只能输入字母数字等。 我正在尝试将@ObservableObject 与@Published var 一起使用,但是,当使用后缀更新值时,文本输入位置不会跳转到输入字段的末尾:

class SignupModel: ObservableObject 
    @Published var phoneNumber: String = "" 
        didSet 
            if (self.phoneNumber.count == 3 || self.phoneNumber.count == 5) 
                if (self.phoneNumber.count == 3) 
                    self.phoneNumber.insert("-", at: String.Index(encodedOffset: 3))
                 else if self.phoneNumber.count == 5 
                    self.phoneNumber.insert("-", at: String.Index(encodedOffset: 5))
                
            
            print(self.phoneNumber)
        
    


...


@ObservedObject var formModel: SignupModel = SignupModel()

...

TextField("12 3333 123", text: self.$formModel.phoneNumber)

使用 combine 实现验证和格式化的有效方法是什么?

【问题讨论】:

试图这样做,但newValue 似乎是不可变的,并且从willSet 修改phoneNumber 值会产生段错误 【参考方案1】:

我最终实现了didSet 以及一个将选择器放置在输入文本字段末尾的自定义 TextField:

class SignupModel: ObservableObject 
    @Published var buttonEnabled = false
    @Published var phoneNumber: String = "" 
        didSet 
            if (self.phoneNumber.count == 13) 
                phoneNumber = oldValue
                self.buttonEnabled = true
                return
            
            buttonEnabled = false
            if ((self.phoneNumber.count == 2 || self.phoneNumber.count == 5 || self.phoneNumber.count == 8)) 
                if (oldValue.last == " ") 
                    phoneNumber.remove(at: oldValue.index(before: phoneNumber.endIndex))
                 else 
                    phoneNumber = phoneNumber + " "
                
            
        
    

下面是来自this 帖子的自定义 TextField 容器:

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)
        
    

我就是这样使用它的:

TextFieldContainer("93 49 99 353", text: self.$formModel.phoneNumber)

【讨论】:

以上是关于如何在附加到 TextField 的 swift @Published didSet 中正确格式化字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中解析到 TextField iOS Keychain?

如何在 Swift 2.0 中使用标签将 TextField 添加到 Cell

SwiftUI:如何使 TextField 适合多行内容?

SwiftUI:如何使 TextField 适合多行内容?

Xcode:如何获取 textLabel 以显示在 textField 中输入的附加静态文本?

我如何在SWIFTUI中把textField作为firstResponder,就像Swift一样:textField.becomesFirstResponder。