SwiftUI TextField - 使用自定义委托绑定值

问题描述 投票:0回答:1

我想对输入到 SwiftUI TextField 中的值进行实时格式化,因此我使用 introspect 添加自定义委托,就像在 UIKit 中一样。这导致 .onChange 停止工作。如果我注释掉委托,.onChange 块就会起作用。如何让绑定与自定义委托一起使用?

文本字段视图:

import Foundation
import SwiftUI


struct TextFieldView: View {
    
    @State private var inputString: String = ""
    
    var customDelegate = CustomTextFieldDelegate()
    
    var body: some View {
        VStack {
            TextField("", text: $inputString)
                .addTextFieldDelegate(delegate: customDelegate)
        }
        .onChange(of: inputString) { _ in
            print("inputString: \(inputString)")
        }
    }
}

反省:

extension View {
    func addTextFieldDelegate(delegate: UITextFieldDelegate) -> some View {
        introspect(.textField, on: .iOS(.v15...)) { textfield in
            textfield.delegate = delegate
        }
    }
}

自定义代表:

class CustomTextFieldDelegate: NSObject, UITextFieldDelegate {
    
    override init() { }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
            return true
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        
        guard let text = textField.text, let textRange = Range(range, in: text) else {
            return false
        }
        
        var updatedText = text.replacingCharacters(in: textRange, with: string)
        updatedText.removeAll(where: {$0 == ":"})
        
        let finalLength = updatedText.count + updatedText.count/2 - 1
        
        if finalLength > 8 {
            return false
        }
        for i in stride(from: 2, to: finalLength, by: 3) {
            let index = updatedText.index(updatedText.startIndex, offsetBy: i)
            updatedText.insert(":", at: index)
        }
        textField.text = updatedText
        
        return false
    }
    

}

编辑01:

我想要实现的是在将输入内容键入文本字段时添加一个“:”每两个字符。我不想使用内省,但不确定如何修改变量 inputString 而不再次触发 onChange 处理程序,从而导致无限循环。

ios swift swiftui uitextfielddelegate
1个回答
0
投票

您不应该依赖 SwiftUI 是基于 UIKit 构建的事实 - 这很可能在未来发生变化。

您不需要使用

UITextFieldDelegate
- 您可以在
onChange
处理程序中执行处理。

例如:

struct ContentView: View {
    
    @State var oldValue = ""
    @State var inputString = ""
    
    var body: some View {
        VStack {
            TextField("XX:XX:XX:XX", text:$inputString)
        }
        .onChange(of: inputString) { newValue in
            self.formatTextField(newValue)
        }
    }
    
    func formatTextField(_ newValue: String) {
        guard self.oldValue != self.code else {
            return
        }
        var finalValue = newValue
        if newValue.count > self.oldValue.count {
            finalValue = self.processInsert(newValue: newValue, oldValue: self.oldValue)
        } else {
            finalValue = self.processDelete( newValue: newValue, oldValue: self.oldValue)
        }
        self.oldValue = finalValue
        self.inputString = finalValue
    }
    
    func processInsert(newValue: String, oldValue:String) -> String {
        guard newValue.count < 12 else {
            return oldValue
        }
        var characters = newValue
        characters.removeAll { $0 == ":"}
        var finalValue = ""
        
        for i in 0..<characters.count {
            finalValue.append(characters[characters.index(characters.startIndex,offsetBy: i)])
            if i < 7 && i > 0 && (i-1) % 2 == 0 {
                finalValue.append(":")
            }
        }
        
        return finalValue
        
    }
    
    func processDelete(newValue: String, oldValue: String) -> String {
        var finalValue = newValue
        var input = finalValue
        input.removeAll { $0 == ":"}
        let length = input.count
        if length > 0 && length % 2 == 0 {
            finalValue = String(finalValue.prefix(finalValue.count-1))
        }
        return finalValue
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.