Reputation: 2127
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:
@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.
Upvotes: 11
Views: 29978
Reputation: 161
Swift 5
func textField(_ textField: UITextField, shouldChangeCharactersIn 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(string: currentString)
default:
if string.count == 0 && currentString.count != 0 {
currentString = String(currentString.dropLast())
formatCurrency(string: currentString)
}
}
return false
}
func formatCurrency(string: String) {
print("format \(string)")
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.currency
formatter.locale = NSLocale(localeIdentifier: "en_US") as Locale
let numberFromField = (NSString(string: currentString).doubleValue)/100
//replace billTextField with your text field name
self.billTextField.text = formatter.string(from: NSNumber(value: numberFromField))
print(self.billTextField.text ?? "" )
}
Upvotes: 1
Reputation: 1
This worked for me: Naming of the variables need to be improved though. Multiplying by 10 was easy but figuring out how to divide by 10 and round down was tricky with the pointers.
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == amountTextField {
guard let text = textField.text else {return true}
let oldDigits = numberFormatter.number(from: text) ?? 0
var digits = oldDigits.decimalValue
if let digit = Decimal(string: string) {
let newDigits: Decimal = digit / 100
digits *= 10
digits += newDigits
}
if range.length == 1 {
digits /= 10
var result = Decimal(integerLiteral: 0)
NSDecimalRound(&result, &digits, 2, Decimal.RoundingMode.down)
digits = result
}
textField.text = NumberFormatter.localizedString(from: digits as NSDecimalNumber, number: .currency)
return false
} else {
return true
}
}
Upvotes: 0
Reputation: 733
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 )
}
Upvotes: 5
Reputation: 1391
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 }
Upvotes: 3
Reputation: 14294
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 )
}
Upvotes: 1
Reputation: 101
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
}
Upvotes: 8
Reputation: 19524
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 )
}
}
Upvotes: 22