问题描述
在SwiftUI中,我想要实现在TextField中,使用NumberFormatter显示千分位和两位小数。

实现效果为,创建了一个inputAmounts字典数组,绑定每一个货币的输入金额。
@State private var inputAmounts: [String: String] = [:]
TextField("0.0", text: Binding(get: {
inputAmounts[currency.symbol ?? ""] ?? ""
}, set: { newValue in
inputAmounts[currency.symbol ?? ""] = newValue
}))
.onChange(of: focusedField) { newFocus in
// 当失去焦点,处理文本框关于 CoreData 方法
if newFocus != .symbol(currency.symbol ?? "") {
handleInputChange(for: currency.symbol ?? "", newValue: inputAmounts[currency.symbol ?? ""] ?? "")
}
}
当TextField发生改变时,TextField失去焦点后,会调用handleInputChange方法。
func handleInputChange(for symbol: String, newValue: String) {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
if let doubleValue = Double(newValue) {
let string = formatter.string(from: NSNumber(value:doubleValue))
inputAmounts[symbol] = string
} else {
print("string计算失败")
}
}
在这个方法中,使用NumberFormatter设置千分位和两位小数。

但是,在实际的测试中发现,当TextField修改为一个小数或者没有小数时,并没有实现真正的两位小数。
同时,Xcode输出“string计算失败”,这也表示handleInputChange方法中Double赋值出现了错误。
问题原因
经过研究发现,问题在于TextField的值中因为包含了千分位分割符,所以在Double(newValue)转换时,因为newValue存在这一问题,所以转换失败了。
Double(3,434.0) // 无法处理千分位分割符
具体来说,是NumberFormatter 的 number(from:) 方法无法正确解析包含千分位(例如 3,434.0)的字符串,因为它期望的是一个符合当前区域数字格式的字符串。例如,在美国地区,千分位分隔符是 ” ,” ,而在一些其他地区,可能是 “.” 。
解决方案
手动移除输入中的千分位分隔符(,),然后再进行转换。
func handleInputChange(for symbol: String, newValue: String) {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
formatter.locale = Locale(identifier: "en_US") // 强制使用美国区域
if let doubleValue = Double(newValue) {
let string = formatter.string(from: NSNumber(value:doubleValue))
inputAmounts[symbol] = string
} else {
print("string计算失败")
}
}
通过 replacingOccurrences(of: “,”, with: “”),移除所有千分位分隔符,这样 NumberFormatter 就可以正确地解析数字。

总结
去除千分位分隔符,如果输入值包含千分位分隔符(,),需要在转换前移除它。从而实现NumberFormatter的正确转换。
相关文章
1、SwiftUI格式化数字的NumberFormatter:https://fangjunyu.com/2025/04/15/swiftui%e6%a0%bc%e5%bc%8f%e5%8c%96%e6%95%b0%e5%ad%97%e7%9a%84numberformatter/
2、SwiftUI保留两位小数和千分位分隔符:https://fangjunyu.com/2025/01/08/swiftui%e4%bf%9d%e7%95%99%e4%b8%a4%e4%bd%8d%e5%b0%8f%e6%95%b0%e5%92%8c%e5%8d%83%e5%88%86%e4%bd%8d%e5%88%86%e9%9a%94%e7%ac%a6/