以下代码加载正常,文本和双精度字段均显示为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)
}
}
答案 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内置支持要好得多,并且还支持与语言环境有关的十进制分隔符
用法
TextField(“ 0”,文本:绑定)