SwiftUI TextField с форматером не работает?
Я пытаюсь обновить числовое поле, поэтому я использую TextField с набором параметров formatter :. Он отлично форматирует число в поле ввода, но не изменяет связанное значение при редактировании. TextField работает нормально (на строках) без указанного форматера. Это ошибка или я что-то упустил?
ОБНОВЛЕНИЕ: Начиная с Xcode 11 beta 3, это вроде работает. Теперь, если вы редактируете числовое TextField, значение привязки обновляется после нажатия клавиши return. String TextField по-прежнему обновляется после каждого нажатия клавиши. Я предполагаю, что они не хотят отправлять значение для форматирования в средство форматирования при каждом нажатии клавиши, или, может быть, есть/будет модификатор для TextField, который скажет ему сделать это.
Обратите внимание, что API немного изменился; старые initF) TextField устарели, и новое поле titleKey String было добавлено в качестве первого параметра, который появляется в качестве текста-заполнителя в поле.
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")
}
}
}
}
Если вы введете первый (String) TextField, значение в текстовом представлении будет обновлено немедленно. Если вы редактируете второй (Числовой), ничего не происходит. Аналогично нажатие кнопки показывает обновленное значение для строки, но не число. Я только попробовал это в симуляторе.
Ответы
Ответ 1
Вы можете использовать Binding для преобразования Double & lt; → String для 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)")
}
}
}
Вы можете использовать вычисляемое свойство для решения этой проблемы. (спасибо @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)")
}
}
}
Ответ 2
Похоже, что при использовании value:
в качестве входных данных SwiftUI не перезагружает представление для любой клавиши, на которую нажимают пользователи. И, как вы упомянули, он перезагружает представление, когда пользователи покидают поле или фиксируют его.
С другой стороны, SwiftUI перезагружает представление (немедленно), используя text:
в качестве ввода при каждом нажатии клавиши. Больше ничего не приходит мне в голову.
в моем случае я сделал это для 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)")
}
}
}