文本字段未更新

时间:2020-03-03 16:48:48

标签: swiftui

以下代码加载正常,文本和双精度字段均显示为300。但是,当我单击“提交”时,文本仅更改为0。您将在打印输出中看到以新值0调用了init,但是它不会更新double字段吗?有什么建议吗?

import SwiftUI

struct ContentView: View {
    @State var amount:Double = 300
    var body: some View {
        VStack {
            Text("\(self.amount)")
            DoubleField(value: $amount)
            Button(action: {self.amount=0}) {Text("Submit")}
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

struct DoubleField:View {

    @Binding var doubleValue:Double
    @State var stringValue:String

    init(value: Binding<Double>) {
        print("DoubleField.init(value: \(value.wrappedValue))")
        self._doubleValue = value
        self._stringValue = State(initialValue: "\(value.wrappedValue)")
    }

    var body: some View {
        TextField("0.00", text: $stringValue)
    }

}

1 个答案:

答案 0 :(得分:0)

SwiftUI不知道DoubleField View的内部状态已更改。在您设置_stringValue时,DoubleField实例仍然不存在,这就是为什么您不能在init(..)中写入stringValue = ...的原因,状态属性包装器只能在初始化,其包装值被更改,而不是之前。

尝试下一个

import SwiftUI

struct ContentView: View {
    @State var amount:Double = 300
    var body: some View {
        VStack {
            Text("\(self.amount)")
            DoubleField(value: $amount).id(amount)
            Button(action: {
                self.amount += 10
            }) { Text("Submit") }
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

struct DoubleField:View {

    @Binding var doubleValue:Double
    @State var stringValue:String
    init(value: Binding<Double>) {
        print("DoubleField.init(value: \(value.wrappedValue))")
        self._doubleValue = value
        self._stringValue = State(initialValue: "\(value.wrappedValue)")
        print(stringValue)
    }

    var body: some View {
        VStack {
        Text(stringValue)
        TextField("20.00", text: $stringValue)
        }
    }

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

所有字段均按要求进行更新,因为SwiftUI会由于.id修饰符而看到更改

就您而言,只需使用

DoubleField(value: $amount).id(amount)

之所以能够工作,是因为Double符合Hashable,并且只有在金额值更改时才会重新计算其主体。

更新

您可以创建自定义绑定,就像我在下一个示例中所做的那样。它与绑定有@State的后端Double值绑定(以将其值的任何更改通知SwiftUI)

let binding = Binding<String>(get: {
            if self.empty { return "" } else {
                return self.format(value: self.value.value)
            }
        }) { (str) in
            self.empty = str.isEmpty
            // before string to double
            // replace decimal separator to "." !!!
            let dot = Locale.current.decimalSeparator ?? "."
            let s = str.replacingOccurrences(of: dot, with: ".")
            self.value.value = Double(s) ?? 0.0
        }

其中

func format(value: Double) -> String {
        // for presentation
        // replace "." with decimal separator
        let dot = Locale.current.decimalSeparator ?? "."
        var s = String(format: "%f", value)
        .replacingOccurrences(of: ".", with: dot)
        .reversed()
        .drop(while: {$0 == "0"})
        .reversed()
        .map(String.init)
        .joined()

        if let last = s.last, String(last) == dot {
            s.removeLast()
        }
        return s
    }

与TextField一起使用,它比TextField中的Formatter内置支持要好得多,并且还支持与语言环境有关的十进制分隔符

示例用法 enter image description here

用法

TextField(“ 0”,文本:绑定)

相关问题