UITextField 显示格式为没有小数的货币

Posted

技术标签:

【中文标题】UITextField 显示格式为没有小数的货币【英文标题】:UITextField display formatted as currency without decimal 【发布时间】:2016-12-21 05:46:16 【问题描述】:

我正在尝试创建一个UITextField,即使用户正在编辑,输入也会以货币格式永久显示。它应该像这样工作:

$0

用户类型 1

$1

用户类型 2

$12

用户类型 0

$120

用户类型 0

$1,200

用户类型 0

$12,000

我设法使用NumberFormatter like 获得最终格式

textField.text = (numberFormatter.string(from: NSNumber(value: Int(textField.text!)!)))?.components(separatedBy: ".")[0]

但是一旦我在 textField 中格式化了文本,后续的输入就会导致如下错误:

$1,000

用户类型 0

$1,0000 //number formatter cannot recognise this as a format of currency

无论如何我可以操纵输入以允许用户只需要键入数字,但该值以正确的货币格式显示,带有符号加逗号 - 例如 $1,200,000。不管数字的多少——但逻辑上最多 10 位就足够了。

我当前的textFieldshouldChangeCharactersInRange是这样的:

    textField.text = numberFormatter.number(from: textField.text!)?.description

    if(range.length == 1)  //Backspace
        if(textField.text?.characters.count == 1)
            textField.text = "$0"
            return false
        
        return true
    
    if(string.trimmingCharacters(in: CharacterSet.decimalDigits.inverted) == "")
        textField.text = (numberFormatter.string(from: NSNumber(value: Int(textField.text!)!)))?.components(separatedBy: ".")[0]
        return false
    
    if(string == ".") 
        textField.text = (numberFormatter.string(from: NSNumber(value: Int(textField.text!)!)))?.components(separatedBy: ".")[0]
        return false
    

    textField.text = (numberFormatter.string(from: NSNumber(value: Int(textField.text!.append(string)!)!)))?.components(separatedBy: ".")[0]
    return false

【问题讨论】:

如果有人能提供帮助我减少括号数量并使代码看起来更简洁而无需添加太多行的提示,我将不胜感激。 【参考方案1】:

试试下面的代码

extension ViewController: UITextFieldDelegate 

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 

        let text: NSString = (textField.text ?? "") as NSString
        let finalString = text.replacingCharacters(in: range, with: string)

        // 'currency' is a String extension that doews all the number styling
        amountTextField.text = finalString.currency

        // returning 'false' so that textfield will not be updated here, instead from styling extension
        return false
    


extension String 
    var currency: String 
        // removing all characters from string before formatting
        let stringWithoutSymbol = self.replacingOccurrences(of: "$", with: "")
        let stringWithoutComma = stringWithoutSymbol.replacingOccurrences(of: ",", with: "")

        let styler = NumberFormatter()
        styler.minimumFractionDigits = 0
        styler.maximumFractionDigits = 0
        styler.currencySymbol = "$"
        styler.numberStyle = .currency

        if let result = NumberFormatter().number(from: stringWithoutComma) 
            return styler.string(from: result)!
        

        return self
    

【讨论】:

这很聪明!我一直在考虑使用数字格式化程序来维护我的字符串,我完全错过了这种可能性 如果我们在中间输入数字,光标会移到末尾,有什么解决办法吗? 真的很干净,谢谢@Matt,有一个问题,有没有办法让最大值只有10位数? (包括货币符号和逗号)【参考方案2】:

您可以使用 UITextField 的 leftView 和 rightView 属性,如下所示:这将只负责在输入字段的左侧显示“$”符号。

override func viewDidLoad() 
        super.viewDidLoad()

        let label = UILabel(frame: CGRect(x :0,y :0,width :10,height: 10))
        label.text = "$"

        self.moneyTextField.leftViewMode = .always
        self.moneyTextField.leftView = label

    

【讨论】:

实际上,我对货币符号没有太大问题,因为数字格式化程序会帮助处理它。我遇到麻烦的是逗号“,”。一旦用户输入超过 4 个数字,它将破坏格式【参考方案3】:
//  ViewController.swift
//  TextfieldDemo
//
//  Created by piyush sinroja on 21/12/16.


import UIKit

class ViewController: UIViewController, UITextFieldDelegate 

    @IBOutlet weak var txtDigit: UITextField!

    var strDigit: String = String()

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let label = UILabel(frame: CGRect(x :0,y :0,width :10,height: 10))
        label.text = "$"
        self.txtDigit.leftViewMode = .always
        self.txtDigit.leftView = label

        txtDigit.layer.cornerRadius = 4.0
        txtDigit.layer.masksToBounds = true
        txtDigit.layer.borderColor = UIColor.lightGray.cgColor
        txtDigit.layer.borderWidth = 1.0
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    func textFieldDidBeginEditing(_ textField: UITextField) 

    

    func textFieldDidEndEditing(_ textField: UITextField) 

    

    func textFieldShouldReturn(_ textField: UITextField) -> Bool 
        return true
    

    func textField(_ textFieldToChange: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 
        if  textFieldToChange == txtDigit
            let aSet = NSCharacterSet(charactersIn:"0123456789").inverted
            let compSepByCharInSet = string.components(separatedBy: aSet)
            let numberFiltered = compSepByCharInSet.joined(separator: "")

            if numberFiltered == "" 
                let new  = txtDigit.text!
                let fsf = new.substring(to: new.index(new.endIndex, offsetBy: -1))
                let currentString = fsf
                let findStr = commaStrSet(currentString: currentString)
                txtDigit.text = findStr
                return false
            
            else
                let currentString = (textFieldToChange.text! as NSString)
                    .replacingCharacters(in: range, with: string)
                let findStr = commaStrSet(currentString: currentString)
                txtDigit.text = findStr
            
        
        return false
    

    func commaStrSet(currentString: String) -> String 
        var replaceStr = currentString.replacingOccurrences(of: ",", with: "")
        let length = replaceStr.characters.count
        switch length 
        case 4:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 1))
        case 5:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 2))
        case 6:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 1))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 5))
        case 7:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 2))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 5))
        case 8:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 1))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 4))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 7))
        case 9:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 2))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 5))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 8))
        case 10:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 1))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 4))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 7))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 10))
        case 11,12,13,14,15:
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 1))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 4))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 7))
            replaceStr.insert(",", at: replaceStr.index(replaceStr.startIndex, offsetBy: 10))
        default:
            break
        

        return replaceStr
    

【讨论】:

我尝试了代码,似乎偏移量是错误的,我试图纠正它。感谢您的帮助。 没有它的工作正常。我只为你做了,你可以用你自己的逻辑 我尝试了另一种尝试使其与字符符号一起使用 - 以后需要改进。我仔细检查了一下,你的偏移量真的错了。返回值有“$,100”、“$1,00,000”和“$,10,00,00,000” @PiyushSinroja 你没有让亿万富翁有机会正确格式化他们的资产(又名“硬编码和幻数是邪恶的”)

以上是关于UITextField 显示格式为没有小数的货币的主要内容,如果未能解决你的问题,请参考以下文章

java中 DecimalFormat格式的定义

带有 4 位小数的货币格式正则表达式,如果没有则不显示美分

尝试将 UITextField 格式化为像货币计算器一样仅用于 iOS 中的数字输入

DecimalFormat(数字格式)

sap货币位数

如何使用 TextWatcher Android 将 3 位小数货币格式添加到edittext