Joji
Joji

Reputation: 33

Formatting currency in Textfield while typing

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)

Upvotes: 0

Views: 238

Answers (1)

Sweeper
Sweeper

Reputation: 270733

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

Upvotes: 2

Related Questions