如何使用Swift在文本字段(从右到左)输入货币格式?

Bol*_*olo 45 uitextfield nsnumberformatter ios swift swift3

我有一个数字可以说0.00.

  • 当用户点击1.我们应该 0.01
  • 当用户点击2.我们应该显示 0.12
  • 当用户点击3.我们应该显示 1.23
  • 当用户点击4.我们应该显示 12.34

我怎么能用Swift做到这一点?

Vla*_*iak 76

对于Swift 3.在文本字段上输入货币格式(从右到左)

override func viewDidLoad() {
    super.viewDidLoad()

    textField.addTarget(self, action: #selector(myTextFieldDidChange), for: .editingChanged)
}

func myTextFieldDidChange(_ textField: UITextField) {

    if let amountString = textField.text?.currencyInputFormatting() {
        textField.text = amountString
    }
}

extension String {

    // formatting text for currency textField
    func currencyInputFormatting() -> String {

        var number: NSNumber!
        let formatter = NumberFormatter()
        formatter.numberStyle = .currencyAccounting
        formatter.currencySymbol = "$"
        formatter.maximumFractionDigits = 2
        formatter.minimumFractionDigits = 2

        var amountWithPrefix = self

        // remove from String: "$", ".", ","
        let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
        amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count), withTemplate: "")

        let double = (amountWithPrefix as NSString).doubleValue
        number = NSNumber(value: (double / 100))

        // if first number is 0 or all numbers were deleted
        guard number != 0 as NSNumber else {
            return ""
        }

        return formatter.string(from: number)!
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案有一些问题.此答案假定使用固定货币符号的固定货币格式.为什么?只有一些国家使用`$`符号.并非所有国家/地区都使用两位小数的货币. (4认同)
  • 实际上,当货币显示在金额的右侧时,这是行不通的(取决于地区电话设置)-那么您无法删除该值 (3认同)
  • 这个非常酷并且工作正常,但是有没有办法使用键盘上的删除按钮删除最后输入的数字?目前,按下按钮时没有任何反应。感谢您的帮助! (2认同)
  • 这很奇怪,但你的例子不起作用,我尝试了另一个解决方案,但删除按钮没有任何作用,所以我想我必须进一步调查...... (2认同)

Leo*_*bus 27

您可以创建子类化UITextField的货币文本字段.为UIControlEvents .editingChanged添加目标.添加选择器方法以过滤文本字符串中的数字.过滤掉字符串中的所有非数字后,您可以使用NumberFormatter再次格式化您的数字,如下所示:

Swift 4.2或更高版本

import UIKit

class CurrencyField: UITextField {
    var decimal: Decimal { string.decimal / pow(10, Formatter.currency.maximumFractionDigits) }
    var maximum: Decimal = 999_999_999.99
    private var lastValue: String?
    var locale: Locale = .current {
        didSet {
            Formatter.currency.locale = locale
            sendActions(for: .editingChanged)
        }
    }
    override func willMove(toSuperview newSuperview: UIView?) {
        print(#function)
        // you can make it a fixed locale currency if needed
        // self.locale = Locale(identifier: "pt_BR") // or "en_US", "fr_FR", etc
        Formatter.currency.locale = locale
        addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        keyboardType = .numberPad
        textAlignment = .right
        sendActions(for: .editingChanged)
    }
    override func deleteBackward() {
        text = string.digits.dropLast().string
        // manually send the editingChanged event
        sendActions(for: .editingChanged)
    }
    @objc func editingChanged() {
        guard decimal <= maximum else {
            text = lastValue
            return
        }
        text = decimal.currency
        lastValue = text
        print("doubleValue:", doubleValue)
    }
}
Run Code Online (Sandbox Code Playgroud)
extension CurrencyField {
    var doubleValue: Double { (decimal as NSDecimalNumber).doubleValue }
}
Run Code Online (Sandbox Code Playgroud)

  • 你写了一行:`let cleanText = String(Array(sender.text).map {String($ 0)}.filter {$ 0.toInt()!= nil} .map {Character($ 0)})as NSString`.为什么要做这么复杂的陈述?用临时变量将其分成3或4个部分.它使得读取,调试和维护变得更加容易,并且编译器优化了发布版本中的临时变量. (3认同)

NSE*_*nal 8

我从 Leo Dabus 的回答开始(这对我来说不是开箱即用的),在试图简化并使其工作的过程中最终得到了这个,如果我这么说的话,我认为它非常简洁和干净我

class CurrencyTextField: UITextField {

    /// The numbers that have been entered in the text field
    private var enteredNumbers = ""

    private var didBackspace = false

    var locale: Locale = .current

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    private func commonInit() {
        addTarget(self, action: #selector(editingChanged), for: .editingChanged)
    }

    override func deleteBackward() {
        enteredNumbers = String(enteredNumbers.dropLast())
        text = enteredNumbers.asCurrency(locale: locale)
        // Call super so that the .editingChanged event gets fired, but we need to handle it differently, so we set the `didBackspace` flag first
        didBackspace = true
        super.deleteBackward()
    }

    @objc func editingChanged() {
        defer {
            didBackspace = false
            text = enteredNumbers.asCurrency(locale: locale)
        }

        guard didBackspace == false else { return }

        if let lastEnteredCharacter = text?.last, lastEnteredCharacter.isNumber {
            enteredNumbers.append(lastEnteredCharacter)
        }
    }
}

private extension Formatter {
    static let currency: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        return formatter
    }()
}

private extension String {
    func asCurrency(locale: Locale) -> String? {
        Formatter.currency.locale = locale
        if self.isEmpty {
            return Formatter.currency.string(from: NSNumber(value: 0))
        } else {
            return Formatter.currency.string(from: NSNumber(value: (Double(self) ?? 0) / 100))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)