Спасибо workingdog за , что было почти ответом. Это не сработало с форматером, но дало мне идею, что сработало.
Форматирование прямо внутри привязки не работает, потому что курсор иногда перепрыгивает после форматирования.
Сначала форматирование моего ca sh:
let cashFormat = getCashFormat()
func getCashFormat() -> NumberFormatter {
let thisCashFormat = NumberFormatter()
thisCashFormat.numberStyle = NumberFormatter.Style.currency
thisCashFormat.roundingMode = NumberFormatter.RoundingMode.halfEven
// halfEven rounding is sometimes referred to as Bankers’ rounding.
thisCashFormat.maximumFractionDigits = 2
return thisCashFormat
}
cashFormat
вернет ноль, если строка не имеет $ в качестве первого символа. Мне нужен еще один NumberFormatter
.
let basicFormat = getBasicFormat()
func getBasicFormat() -> NumberFormatter {
let thisBasicFormat = NumberFormatter()
thisBasicFormat.numberStyle = NumberFormatter.Style.decimal
thisBasicFormat.roundingMode = NumberFormatter.RoundingMode.halfEven
thisBasicFormat.minimumFractionDigits = 0
thisBasicFormat.maximumFractionDigits = 6
return thisBasicFormat
}
basicFormat
, который возвращает больше цифр дроби, чем мне нужно, но я буду преобразовывать двойные числа в целочисленные центы в другом месте моего приложения, прежде чем модель сохранит их.
Я создал ObservableObject
класс для форматирования.
class FieldFormatter: ObservableObject {
@Binding var dollars: Double
@Published var dollarText: String
init(dollars: Binding<Double>) {
self._dollars = dollars
self.dollarText = dollars.wrappedValue.cash()
}
func dollarsChanged() {
if let thisNumber = cashFormat.number(from: dollarText) {
self.dollars = thisNumber.doubleValue
} else if let thisNumber = basicFormat.number(from: dollarText) {
self.dollars = thisNumber.doubleValue
}
}
}
Наконец, вот моя структура TextField.
struct CashFieldC: View {
var thisLabel: String
@Binding var dollars: Double
@ObservedObject var fieldFormatter: FieldFormatter
init(thisLabel: String, dollars: Binding<Double>) {
self.thisLabel = thisLabel
self._dollars = dollars
self.fieldFormatter = FieldFormatter(dollars: dollars)
}
var body: some View {
VStack(alignment: .leading) {
Text(thisLabel).font(.caption)
TextField(thisLabel, text: $fieldFormatter.dollarText, onEditingChanged: { (oec) in
if !oec {
self.fieldFormatter.dollarsChanged()
}
})
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.numbersAndPunctuation)
}
}
}
Значение dollarText
устанавливается, когда FieldFormatter
объект инициализирован. Привязка в TextField
обновляет его каждый раз, когда вводится символ.
Переменная, связанная в поле форматирования, обновляется только тогда, когда поле фиксируется при нажатии возврата.
Форматирование внутри Привязка близко к ответу Workingdog заставит курсор перескочить после ввода каждого di git.
Эта структура использует закрытие onEditingChanged:
для обновления привязки dollars
, когда поле теряет фокус из-за нажатия возврата или при выборе другого поля. Закрытие попытается сначала выполнить форматирование ca sh или двойное форматирование basi c, если форматирование ca sh завершится неудачей.