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)")
    }
  }
}