I need to format the currency while typing in TextField
. I have tried many answers but nothing worked in my case. My currency is INR. When the user types it should change from, for example "1200" to "₹1,200". I am able to convert it to "₹1200", but the comma is missing.
My implementation:
extension NumberFormatter {
static var currencyFormatter: NumberFormatter {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "₹"
formatter.maximumFractionDigits = 0
formatter.usesGroupingSeparator = true
formatter.currencyCode = "INR"
formatter.currencyGroupingSeparator = ","
formatter.groupingSeparator = ","
formatter.maximumIntegerDigits = 10
formatter.locale = Locale(identifier: "en_IN")
return formatter
}
}
@State var testAmount = String()
TextField("₹ 0", text: $testAmount)
.onChange(of: testAmount){newvalue in
if let parsedAmount = Double(newvalue){
self.testAmount = NumberFormatter.currencyFormatter.string(from: NSNumber(value: parsedAmount)) ?? ""
}
}
.keyboardType(.numberPad)
Double(newvalue)
will fail to parse the string once it has a ₹
in it.
You can parse and format the number using the FormatStyle
APIs. You can use a Decimal.FormatStyle.Currency
.
@State private var testAmount = ""
let formatStyle = Decimal.FormatStyle.Currency
.currency(code: "INR")
.precision(.fractionLength(0))
.locale(.init(identifier: "en_IN"))
var body: some View {
TextField("₹ 0", text: $testAmount)
.onChange(of: testAmount){ _, newValue in
if let parsedAmount = try? formatStyle.parseStrategy.parse(newValue) {
self.testAmount = formatStyle.format(parsedAmount)
}
}
}
In my opinion though, formatting while typing is rather confusing. Formatting after the user ends editing is a much better user experience. TextField
has a dedicated initialiser for this:
@State private var testAmount: Decimal = 0
let formatStyle = Decimal.FormatStyle.Currency
.currency(code: "INR")
.precision(.fractionLength(0))
.locale(.init(identifier: "en_IN"))
var body: some View {
TextField("₹ 0", value: $testAmount, format: formatStyle)
}