【问题标题】:How to get bound value of a TextField to update when you tap another TextField?当您点击另一个 TextField 时,如何获取要更新的 TextField 的绑定值?
【发布时间】:2020-04-09 13:20:44
【问题描述】:

如果我使用以下内容创建 SwiftUI 文本字段:

init<S, T>(_ title: S, value: Binding<T>, formatter: Formatter)

它仅在按下 Return 时更新绑定值。如果我在按下 return 之前选择了不同的字段,第一个字段仍会显示其新值,但绑定的变量不会更新。

下面的初始化似乎 onEditingChanged 可能对我有帮助,

init<S, T>(_ title: S, value: Binding<T>, formatter: Formatter, onEditingChanged: @escaping (Bool) -> Void = { _ in }, onCommit: @escaping () -> Void = {})

但此时documentation 几乎是空的。较早的 question 似乎相似,但没有公布答案,可能早于上面的第二个 init。

如果绑定值未更新,在 OnCommit 操作中,我如何抓取 TextField 中显示的字符串以对其进行格式化/将其转换为数字?

【问题讨论】:

    标签: ios swiftui textfield


    【解决方案1】:

    试试这样的:

    struct ContentView: View {
    
    @State var test1 = "test1"
    @State var test2 = "test2"
    
    var body: some View {
        VStack {
            TextField(test1, text: Binding(get: {
                self.test1
            }, set: { newVal in
                self.test1 = newVal
                self.test2 = newVal
            }))
            TextField(test2, text: $test2)
        }
    }
    

    【讨论】:

    • 这不适用于formatter 的构造函数,请仔细阅读问题。
    • 正确,它不适用于格式化程序,因为我知道这是一个错误。然而,问题“当您点击另一个 TextField 时,如何获取要更新的 TextField 的绑定值?”用另一种方法回答。
    【解决方案2】:

    感谢workingdog what was almost the answer. 它不适用于格式化程序,但它给了我有效的想法。

    在绑定内直接格式化不起作用,因为光标有时会在格式化后跳来跳去。

    首先是我的现金格式化程序:

    let cashFormat = getCashFormat()
    func getCashFormat() -> NumberFormatter {
        let thisCashFormat = NumberFormatter()
        thisCashFormat.numberStyle = NumberFormatter.Style.currency
        thisCashFormat.roundingMode = NumberFormatter.RoundingMode.halfEven
        // halfEven rounding is sometimes referred to as Bankers’ rounding.
        thisCashFormat.maximumFractionDigits = 2
        return thisCashFormat
    }
    

    cashFormat 如果字符串的第一个字符没有 $,格式化将返回 nil。我需要另一个NumberFormatter。

    let basicFormat = getBasicFormat()
    func getBasicFormat() -> NumberFormatter {
        let thisBasicFormat = NumberFormatter()
        thisBasicFormat.numberStyle = NumberFormatter.Style.decimal
        thisBasicFormat.roundingMode = NumberFormatter.RoundingMode.halfEven
        thisBasicFormat.minimumFractionDigits = 0
        thisBasicFormat.maximumFractionDigits = 6
        return thisBasicFormat
    }
    

    basicFormat 返回的小数位数比我需要的多,但在模型存储它之前,我会在我的应用程序的其他地方将双精度数转换为整数美分。

    我为格式化创建了一个ObservableObject 类。

    class FieldFormatter: ObservableObject {
        @Binding var dollars: Double
        @Published var dollarText: String
    
        init(dollars: Binding<Double>) {
            self._dollars = dollars
            self.dollarText = dollars.wrappedValue.cash()
        }
    
        func dollarsChanged() {
            if let thisNumber = cashFormat.number(from: dollarText) {
                self.dollars = thisNumber.doubleValue
            } else if let thisNumber = basicFormat.number(from: dollarText) {
                self.dollars = thisNumber.doubleValue
            }
        }
    }
    

    最后,这是我的 TextField 结构。

    struct CashFieldC: View {
    
        var thisLabel: String
        @Binding var dollars: Double
        @ObservedObject var fieldFormatter: FieldFormatter
    
        init(thisLabel: String, dollars: Binding<Double>) {
            self.thisLabel = thisLabel
            self._dollars = dollars
            self.fieldFormatter = FieldFormatter(dollars: dollars)
        }
    
        var body: some View {
            VStack(alignment: .leading) {
                Text(thisLabel).font(.caption)
                TextField(thisLabel, text: $fieldFormatter.dollarText, onEditingChanged: { (oec) in
                    if !oec {
                        self.fieldFormatter.dollarsChanged()
                    }
                })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .keyboardType(.numbersAndPunctuation)
            }
        }
    }
    

    dollarText 值在 FieldFormatter 对象初始化时设置。 TextField 中的绑定会在每次输入字符时更新。

    格式字段中的绑定变量仅在该字段在点击返回时提交时才会更新。

    在接近工作狗答案的绑定内格式化会导致光标在输入每个数字后跳来跳去。

    此结构使用onEditingChanged: 闭包来更新dollars 绑定,当该字段因点击返回或而失去焦点时选择另一个字段。如果现金格式化失败,闭包将首先尝试现金格式化或基本的双重格式化。

    【讨论】:

    • 这很有帮助,但是 FieldFormatter init() 中的 dollar.wrappedValue.cash() 背后的实现是什么?
    • Double func cash() 的扩展 -> String { if let cashString = cashFormat.string(from: NSNumber(value: self)) { return cashString } else { return "$$$curious 现金扩展错误$$$" } }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-10
    • 1970-01-01
    • 2020-06-03
    • 2020-05-24
    • 2021-04-03
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多