Search code examples
iosswiftuitextfieldnsnumberformatter

Can't get UITextField to populate when using .currency format of NumberFormatter()


I borrowed and modified some code from SO to solve a problem where I was trying to format text that I inputted into my UITextFields. If I use the .decimal numberStyle of NumberFormatter it works (adds a comma where I need it) but if I use .currency I can't type anything once I run the app. The UITextField will not populate.

I've tried playing around with the locale and that doesn't seem to solve anything.

All I want to do is to show the user the "$" sign in front of the number they type as soon as they start typing into the UITextField

It's doing it with or without the digitsOnly extension I'm using, so that doesn't seem to be causing it.

Relevant code:

case annualBill!:
    if isNumeric {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.currencySymbol = "$"

        let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
        let numberWithOutCommas = newString.replacingOccurrences(of: ",", with: "")
        let number = formatter.number(from: numberWithOutCommas)
        if number != nil {
            let formattedString = formatter.string(from: number!)
            textField.text = formattedString
            values.annualBill = Decimal(string: (textField.text?.digitsOnly)!)
            print(values.annualBill ?? "NA")
        } else {
            textField.text = nil
        }

extension String {
    var digitsOnly: String {
        return components(separatedBy: 
    NSCharacterSet.decimalDigits.inverted).joined(separator: "")
        }
    }

Solution

  • Try this in your text field delegate.

    var amountString = ""
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
        if !string.isValidCharacterForCurrency() {
            return false
        }
    
        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = 2
        formatter.maximumFractionDigits = 2
    
        if string.count > 0 {
            amountString += string
            let decNumber = NSDecimalNumber(string: amountString).multiplying(by: 0.01)
            let newString = "$" + formatter.string(from: decNumber)!
            textField.text = newString
    
        }
        else {
    
            amountString = String(amountString.dropLast())
            if amountString.count > 0 {
                let decNumber = NSDecimalNumber(string: amountString).multiplying(by: 0.01)
                let newString = "$" +  formatter.string(from: decNumber)!
                textField.text = newString
            }
            else {
                textField.text = "$0.00"
            }
        }
        return false
    }
    
    extension String {
    
        func isValidCharacterForCurrency() -> Bool {
    
            let intValue = Int(self)
            return !(intValue == 0 && self != "0" && self != "")
        }
    }