Форматировать валюту в текстовом поле в Swift на входе

Я пытаюсь форматировать ввод валюты в текстовое поле в Swift, когда пользователь вводит его.

До сих пор я мог только форматировать его успешно, когда пользователь заканчивает ввод:

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

Однако я хотел бы, чтобы валюта отформатировалась в тот момент, когда пользователь вводит ее. Когда я пытаюсь сделать это в действиях TextField "Редактирование изменено" или "Изменено значение", я могу ввести только 1 номер (если я нахожу 8, он становится 8,00 долларов США), но затем, когда я ввожу второй номер, все идет до $0.00, а я не может войти дальше.

Любые предложения? Я чувствую, что это должно быть легким решением, но я не могу это понять.

Ответ 1

Я изменил функцию с сегодняшнего дня. Отлично подходит для "en_US" и "fr_FR". Однако для "ja_JP" деление на 100, которое я делаю для создания десятичных знаков, является проблемой. Вам понадобится оператор switch или if/else, который разделяет валюты с десятичными знаками и те, которые их не имеют, если они форматируются форматированием. Но я думаю, что это доставит вас в пространство, в котором вы хотели бы быть.

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

Ответ 2

это работает для меня, используя 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
}

Ответ 3

Основываясь на ответе @Robert. Обновлено для 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 )
}

Ответ 4

Для 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 }

Ответ 5

Я разработал нормальный формат валюты (например, 1 - $1,00, 88885 - $8,8885,00 и 7555,8569 - 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 )
}

Ответ 6

Это сработало для меня: хотя имена переменных необходимо улучшить. Умножить на 10 было легко, но вычислить, как делить на 10 и округлить, было сложно с указателями.

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