Format currency in textfield in Swift on input

I am trying to format currency input in a textfield in Swift as the user inputs it.

So far, I can only format it successfully when the user finishes inputting:

  • Regex capture group swift
  • How to add a magnifier to custom control?
  • iOS NSXMLParsing unformed HTML
  • UISearchBar Not shifting up
  • Blocks on Swift (animateWithDuration:animations:completion:)
  • Swift - Protocol extensions - Property default values
  • @IBAction func editingEnded(sender: AnyObject) {
    
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        formatter.locale = NSLocale(localeIdentifier: "en_US")
        var numberFromField = NSString(string: textField.text).doubleValue
    
        textField.text = formatter.stringFromNumber(numberFromField)
    }
    

    However, I would like for the currency to be formatted the moment the user inputs it. When I try to do it on the TextField actions “Editing Changed” or “Value Changed”, I can only enter 1 number (if I enter 8, it becomes $8.00) but then once I enter a second number everything goes to $0.00 and I cannot enter further beyond that.

    Any suggestions? I feel like this should be an easy fix but I can’t quite get at it.

    5 Solutions Collect From Internet About “Format currency in textfield in Swift on input”

    I modified the function from earlier today. Works great for “en_US” and “fr_FR”. However, for “ja_JP”, the division by 100 I do to create decimals is a problem. You will need to have a switch or if/else statement that separates currencies with decimals and those that do not have them when formatted by the formatter. But I think this gets you in the space you wanted to be.

    import UIKit
    
    class ViewController: UIViewController, UITextFieldDelegate {
    
        @IBOutlet weak var textField: UITextField!
        var currentString = ""
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.textField.delegate = self
        }
    
        //Textfield delegates
        func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { // return NO to not change text
    
            switch string {
            case "0","1","2","3","4","5","6","7","8","9":
                currentString += string
                println(currentString)
                formatCurrency(string: currentString)
            default:
                var array = Array(string)
                var currentStringArray = Array(currentString)
                if array.count == 0 && currentStringArray.count != 0 {
                    currentStringArray.removeLast()
                    currentString = ""
                    for character in currentStringArray {
                        currentString += String(character)
                    }
                    formatCurrency(string: currentString)
                }
            }
            return false
        }
    
        func formatCurrency(#string: String) {
            println("format \(string)")
            let formatter = NSNumberFormatter()
            formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
            formatter.locale = NSLocale(localeIdentifier: "en_US")
            var numberFromField = (NSString(string: currentString).doubleValue)/100
            textField.text = formatter.stringFromNumber(numberFromField)
            println(textField.text )
        }
    }
    

    this works for me using NSNumberFormatter…

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    
        // Construct the text that will be in the field if this change is accepted
        var oldText = textField.text as NSString
        var newText = oldText.stringByReplacingCharactersInRange(range, withString: string) as NSString!
        var newTextString = String(newText)
    
        let digits = NSCharacterSet.decimalDigitCharacterSet()
        var digitText = ""
        for c in newTextString.unicodeScalars {
            if digits.longCharacterIsMember(c.value) {
                digitText.append(c)
            }
        }
    
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        formatter.locale = NSLocale(localeIdentifier: "en_US")
        var numberFromField = (NSString(string: digitText).doubleValue)/100
        newText = formatter.stringFromNumber(numberFromField)
    
        textField.text = newText
    
        return false
    }
    

    Based on @Robert answer. Updated for Swift 2.0

    //Textfield delegates
    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { // return NO to not change text
    
        switch string {
        case "0","1","2","3","4","5","6","7","8","9":
            currentString += string
            formatCurrency(currentString)
        default:
            if string.characters.count == 0 && currentString.characters.count != 0 {
                currentString = String(currentString.characters.dropLast())
                formatCurrency(currentString)
            }
        }
        return false
    }
    
    func formatCurrency(string: String) {
        print("format \(string)")
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        formatter.locale = NSLocale(localeIdentifier: "en_US")
        let numberFromField = (NSString(string: currentString).doubleValue)/100
        self.amountField.text = formatter.stringFromNumber(numberFromField)
        print(self.amountField.text )
    }
    

    For Swift 3.0

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
            // Construct the text that will be in the field if this change is accepted
    
            switch string {
            case "0","1","2","3","4","5","6","7","8","9":
                currentString += string
                formatCurrency(currentString)
            default:
                if string.characters.count == 0 && currentString.characters.count != 0 {
                    currentString = String(currentString.characters.dropLast())
                    formatCurrency(currentString)
                }
            }
            return false    }
    
        func formatCurrency(_ string: String) {
            print("format \(string)")
            let formatter = NumberFormatter()
            formatter.numberStyle = .currency
            formatter.locale = findLocaleByCurrencyCode("NGN")
            let numberFromField = (NSString(string: currentString).doubleValue)/100
            let temp = formatter.string(from: NSNumber(value: numberFromField))
            self.amountTextField.text = String(describing: temp!.characters.dropFirst())
        }
    
    func findLocaleByCurrencyCode(_ currencyCode: String) -> Locale? {
    
        let locales = Locale.availableIdentifiers 
        var locale: Locale?     
        for   localeId in locales {     
          locale = Locale(identifier: localeId)     
          if let code = (locale! as NSLocale).object(forKey: NSLocale.Key.currencyCode) as? String { 
            if code == currencyCode {
                    return locale       
            }   
        } 
    }    
    return locale }
    

    I worked out a normal currency format ( eg 1 is as $1.00, 88885 is as $8,8885.00 and 7555.8569 as $7,555.86.

    @IBAction func lostpropertyclicked(sender: AnyObject) {
        var currentString = ""
        currentString = amountTF.text
        formatCurrency(string: currentString)
    }
    
    func formatCurrency(#string: String) {
        println("format \(string)")
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        formatter.locale = NSLocale(localeIdentifier: "en_US")
        var numberFromField = (NSString(string: currentString).doubleValue)
        currentString = formatter.stringFromNumber(numberFromField)!
        println(currentString )
    }