I'm trying to get a numeric field updated so I'm using a TextField with the formatter: parameter set. It formats the number into the entry field just fine, but does not update the bound value when edited. The TextField works fine (on Strings) without the formatter specified. Is this a bug or am I missing something?
UPDATE: As of Xcode 11 beta 3 it kind of works. Now if you edit the numeric TextField, the bound value is updated after you hit return. The String TextField is still updated after each keypress. I guess they don't want to send the value to be formatted to the formatter with every key press, or maybe there is/will be a modifier for TextField to tell it to do that.
Note that The API has changed slightly; the old TextField init()s are deprecated and a new titleKey String field has been added as the first parameter which appears as placeholder text in the field.
struct TestView : View {
@State var someText = "Change me!"
@State var someNumber = 123.0
var body: some View {
Form {
// Xcode 11 beta 2
// TextField($someText)
// TextField($someNumber, formatter: NumberFormatter())
// Xcode 11 beta 3
TextField("Text", text: $someText)
TextField("Number", value: $someNumber, formatter: NumberFormatter())
Spacer()
// if you change the first TextField value, the change shows up here
// if you change the second (the number),
// it does not *until you hit return*
Text("text: \(self.someText), number: \(self.someNumber)")
// the button does the same, but logs to the console
Button(action: { print("text: \(self.someText), number: \(self.someNumber)")}) {
Text("Log Values")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
If you type in the first (String) TextField, the value in the Text view is updated immediately. If you edit the second (Numeric), nothing happens. Similarly tapping the Button shows an updated value for the String, but not the number. I've only tried this in the simulator.
FRI*_*DAY 10
似乎在value:用作输入时,SwiftUI 不会为用户点击的任何键重新加载视图。而且,正如您所提到的,当用户退出该字段或提交它时,它会重新加载视图。
另一方面,text:每当按下某个键时,SwiftUI 都会(立即)重新加载视图作为输入。我脑子里没有别的东西。
就我而言,我是这样做的someNumber2:
struct ContentView: View {
@State var someNumber = 123.0
@State var someNumber2 = "123"
var formattedNumber : NSNumber {
let formatter = NumberFormatter()
guard let number = formatter.number(from: someNumber2) else {
print("not valid to be converted")
return 0
}
return number
}
var body: some View {
VStack {
TextField("Number", value: $someNumber, formatter: NumberFormatter())
TextField("Number2", text: $someNumber2)
Text("number: \(self.someNumber)")
Text("number: \(self.formattedNumber)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用Binding将Double <->字符串转换为TextField
struct TestView: View {
@State var someNumber = 123.0
var body: some View {
let someNumberProxy = Binding<String>(
get: { String(format: "%.02f", Double(self.someNumber)) },
set: {
if let value = NumberFormatter().number(from: $0) {
self.someNumber = value.doubleValue
}
}
)
return VStack {
TextField("Number", text: someNumberProxy)
Text("number: \(someNumber)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用计算属性方法解决此问题。(感谢@iComputerfreak)
struct TestView: View {
@State var someNumber = 123.0
var someNumberProxy: Binding<String> {
Binding<String>(
get: { String(format: "%.02f", Double(self.someNumber)) },
set: {
if let value = NumberFormatter().number(from: $0) {
self.someNumber = value.doubleValue
}
}
)
}
var body: some View {
VStack {
TextField("Number", text: someNumberProxy)
Text("number: \(someNumber)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
B方案。既然用了value:又NumberFormatter不行,我们可以用一个定制的TextField. 我已经将TextFielda包裹在里面struct,以便您可以尽可能透明地使用它。
我是很新的既雨燕和SwiftUI,所以毫无疑问更优雅的解决方案。
struct IntField: View {
@Binding var int: Int
@State private var intString: String = ""
var body: some View {
return TextField("", text: $intString)
.onReceive(Just(intString)) { value in
if let i = Int(value) { int = i }
else { intString = "\(int)" }
}
.onAppear(perform: {
intString = "\(int)"
})
}
}
Run Code Online (Sandbox Code Playgroud)
并在内容视图中:
struct ContentView: View {
@State var testInt: Int = 0
var body: some View {
return HStack {
Text("Number:")
IntField(int: $testInt);
Text("Value: \(testInt)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,我们使用 a TextField("…", text: …),其行为符合要求,并使用代理文本字段。
与使用value:and的版本不同NumberFormatter,该.onReceive方法立即响应,我们使用它来设置实整数值,这是绑定的。当我们在做的时候,我们检查文本是否真的产生一个整数。
该.onAppear方法用于从整数填充字符串。
您可以对FloatField.
这可能会在 Apple 完成工作之前完成工作。
小智 5
Swift 5.5 和 iOS 15 具有新的格式化 API。
我正在寻找一个干净的货币格式化程序并发现了这个文档。
请参阅此处的文档: ParseableFormatStyle
当您键入时,这仍然不会更新 TextField 绑定值。但是,您不再需要按回车键来触发格式化。您只需退出文本字段即可。当您单击返回文本字段以编辑原始值时,它也会按预期运行。
这是一个工作示例:
import SwiftUI
struct FormatTest: View {
@State var myNumber: Double?
@State var myDate: Date.FormatStyle.FormatInput?
var body: some View {
Form {
TextField("", value: $myNumber, format: .currency(code: "USD"), prompt: Text("Enter a number:"))
TextField("", value: $myDate, format: .dateTime.month(.twoDigits).day(.twoDigits).year(), prompt: Text("MM/DD/YY"))
Text(myDate?.formatted(.dateTime.weekday(.wide)) ?? "")
}
}
}
struct FormatTest_Previews: PreviewProvider {
static var previews: some View {
FormatTest()
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2778 次 |
| 最近记录: |