当您点击另一个 TextField 时,如何获取要更新的 TextField 的绑定值?

Posted

技术标签:

【中文标题】当您点击另一个 TextField 时,如何获取要更新的 TextField 的绑定值?【英文标题】:How to get bound value of a TextField to update when you tap another 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 中显示的字符串以对其进行格式化/将其转换为数字?

【问题讨论】:

【参考方案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 现金扩展错误$$$"

以上是关于当您点击另一个 TextField 时,如何获取要更新的 TextField 的绑定值?的主要内容,如果未能解决你的问题,请参考以下文章

点击另一个 TextField 时,SwiftUI TextField 不会提交更改

JavaFx MVC Getter 抛出 NullPointerException

将文本从Textfield传递到另一个ViewController

Swift 如何在另一个 UITextField 突出显示或具有值时禁用 TextField

SwiftUI 如何获取对 List 内编辑 Textfield 的参考?

用户点击字段时如何将 textFieldStyle 切换为 TextField?