如何处理文本字段中的格式化数字(货币)?

Posted

技术标签:

【中文标题】如何处理文本字段中的格式化数字(货币)?【英文标题】:how to deal with formatted number (currency) in textfield? 【发布时间】:2020-06-12 08:44:53 【问题描述】:
struct PriceField: View 


    @ObservedObject var textFieldManager = TextFieldManager()
    @State var number : Double = 0
    @State var inputString  = ""


    var body: some View 


        HStack
//            Text(format(num: textFieldManager.number))
            Text("\(textFieldManager.number)")
            TextField("RM", value: $textFieldManager.number, formatter: NumberFormatter.currency)
                    UIApplication.shared.endEditing()
            

            .multilineTextAlignment(.trailing)
//            .keyboardType(.numberPad)



        
    



extension NumberFormatter 
    static var currency: NumberFormatter 
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = Locale(identifier: "ms_MY")
        return formatter
    






func format(num: Double) -> String
    let formatter = NumberFormatter()
    formatter.locale = Locale(identifier: "ms_MY")
    formatter.numberStyle = .currency

    if let formattedAmount = formatter.string(from: num as NSNumber) 
        return formattedAmount
    
    else
        return "Formatting error ... "
    





class TextFieldManager: ObservableObject 

    @Published var number : Double = 0 
        didSet
            print("change from:", oldValue, "to:", "\(number)")
        

    



    当我输入 RM12.34255 并按“返回”时,文本字段显示 RM12.34(格式为所需的小数)。然而,它 没有将我的班级财产更新为 RM12.34,而是得到 更新为 RM12.34255。我该如何解决这个问题?

    似乎货币名称(RM)可以被删除并且有一个 用户可以输入没有当前符号的数字的机会 它会产生错误“MultiLineTextView[31301:771480] [SwiftUI] 值“12.34255”无效。”。是否可以使文本 文本字段中的“RM”不可擦除?

更新代码:

func format(num: Double) -> Double
    let doubleStr = String(format: "%.2f", num) // "3.14"
    let doubleNum =  Double(doubleStr)!
    print("doubleStr \(doubleStr), doubleNum \(doubleNum)")
    return doubleNum





class TextFieldManager: ObservableObject 

    @Published var number : Double = 0 
        didSet
            print("change from:", oldValue, "to:", "\(number)")
            formattedNumber = format(num: number)
            print("formattedNumber is : \(formattedNumber)")

        


    

    @Published var formattedNumber : Double = 0




【问题讨论】:

【参考方案1】:

关于问题 (1),请理解格式化只会改变数字的“外观”,如 TextField 所示。它不会改变值。该值仍然是 Double。这就是为什么您的类属性“数字”将是双精度数。 我该如何解决这个问题?你没有,这是正常行为。要以您想要的方式显示此类属性“数字”,请使用 NumberFormatter 或您想要的任何格式化程序。

关于问题(2),尝试“formatter.isLenient = true”,如下代码所示。

这是我用来测试的代码。

import SwiftUI

struct ContentView: View 
var body: some View 
   PriceField()



struct PriceField: View 
@ObservedObject var textFieldManager = TextFieldManager()
var body: some View 
    HStack 
        Text("\(textFieldManager.number)")
        TextField("RM", value: $textFieldManager.number, formatter: NumberFormatter.currency)
    



extension NumberFormatter 
static var currency: NumberFormatter 
    let formatter = NumberFormatter()
    formatter.isLenient = true  //  <--- works without the currency symbol
    formatter.numberStyle = .currency
    formatter.locale = Locale(identifier: "ms_MY")
    return formatter



func format(num: Double) -> String
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "ms_MY")
formatter.numberStyle = .currency
if let formattedAmount = formatter.string(from: num as NSNumber) 
    return formattedAmount
 else 
    return "Formatting error ... "



class TextFieldManager: ObservableObject 
@Published var number : Double = 0 
    didSet
        print("---> change from:", oldValue, "to:", "\(number)")
    


我希望这会有所帮助。

【讨论】:

对于问题(1),好的,我明白了。所以我只是在'number'之上创建另一个类属性'formattedNumber'来解决这个问题。对于问题(2),嗯,这行得通。难道真的没有办法让货币符号在这里,而不是一直被抹去吗? 添加 formatter.isLenient = true 使当前符号在按下“返回”按钮后重新出现,如果它在编辑过程中被删除。但是,在用户编辑文本字段期间保留符号可能是一个理想的属性 处理货币符号的一种方法是在 TextField("", ...) 中不放置任何内容,并在其前面放置一个永久 Text("RM")。 我刚试过,没用。你介意展示一下你是怎么做到的吗?顺便说一句,文本字段对齐在尾随。 Text("RM") TextField("", value: $textFieldManager.number, formatter: NumberFormatter.currency) UIApplication.shared.endEditing() .multilineTextAlignment(.trailing) 这样的; HStack Spacer() Text("RM") TextField("", value: $textFieldManager.number, formatter: NumberFormatter())

以上是关于如何处理文本字段中的格式化数字(货币)?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅使用货币代码将数字格式化为货币?

如何使用 Velocity NumberTool 处理大货币数字

如何获取当前文化格式的数字货币

如何比较货币数字格式的值

如何将数字格式化为货币字符串

如何使用正则表达式将数字格式化为货币