如何用FormatStyle API格式化带SI单位的大额货币数值
用FormatStyle API实现带SI单位的大额货币格式化
可以通过自定义FormatStyle来实现这个需求,原生的货币格式化组件不直接支持SI单位缩写,但我们可以封装一个组合式的格式器,同时兼顾货币符号本地化、数值缩放和SI单位显示。
实现思路
- 定义SI单位对应的缩放规则(比如1M对应10^6)
- 对输入数值进行缩放,匹配对应的SI单位
- 使用原生货币格式化处理缩放后的数值,确保本地化的货币符号正确
- 将SI单位符号追加到格式化后的字符串末尾
完整代码实现
struct CurrencySIFormatStyle: FormatStyle { typealias FormatInput = Double typealias FormatOutput = String let currencyCode: String let precision: FloatingPointFormatStyle<Double>.Precision func format(_ value: Double) -> String { // 定义SI单位阈值、缩放因子和符号 let siUnits: [(threshold: Double, divisor: Double, symbol: String)] = [ (1_000_000_000, 1_000_000_000, "B"), (1_000_000, 1_000_000, "M"), (1_000, 1_000, "k"), (0, 1, "") ] // 匹配当前数值对应的SI单位 let matchedUnit = siUnits.first { abs(value) >= $0.threshold } ?? siUnits.last! let scaledValue = value / matchedUnit.divisor // 利用原生货币格式化处理缩放后的数值,保证本地化适配 let currencyFormatter = FloatingPointFormatStyle<Double>.currency(code: currencyCode) .precision(precision) let formattedCurrency = currencyFormatter.format(scaledValue) return formattedCurrency + matchedUnit.symbol } } // 扩展FormatStyle,提供便捷调用方式 extension FormatStyle where Self == CurrencySIFormatStyle { /// 带SI单位的货币格式化器 /// - Parameters: /// - code: 货币代码(如"usd"、"eur") /// - precision: 数值精度设置 static func currencySI(code: String, precision: FloatingPointFormatStyle<Double>.Precision = .significantDigits(2)) -> CurrencySIFormatStyle { CurrencySIFormatStyle(currencyCode: code, precision: precision) } // 对应原有需求的美元SI格式化器 static var dollarsSI: CurrencySIFormatStyle { .currencySI(code: "usd", precision: .significantDigits(2)) } }
使用示例
// 大额数值格式化 let twentyMillion = Double(20_000_000) print(twentyMillion.formatted(.dollarsSI)) // 输出 "$20M" // 更大数值 let onePointFiveBillion = Double(1_500_000_000) print(onePointFiveBillion.formatted(.dollarsSI)) // 输出 "$1.5B" // 小额数值(不触发SI单位) let fiveHundred = Double(500) print(fiveHundred.formatted(.dollarsSI)) // 输出 "$500" // 负数处理 let negativeTenThousand = Double(-10_000) print(negativeTenThousand.formatted(.dollarsSI)) // 输出 "-$10k" // 本地化适配(比如切换到英国Locale) Locale.current = Locale(identifier: "en_GB") print(twentyMillion.formatted(.dollarsSI)) // 输出 "US$20M"
扩展说明
- 单位扩展:如果需要支持更大/更小的SI单位(如万亿"T"、毫"m"),只需在
siUnits数组中添加对应的条目即可 - 精度调整:可以通过修改
precision参数控制数值显示精度,比如.fractionLength(0)强制显示整数,.significantDigits(3)显示3位有效数字 - 本地化兼容:依赖原生
currency(code:)的本地化能力,货币符号会根据当前Locale自动调整,符合不同地区的显示习惯
内容的提问来源于stack exchange,提问作者Rob Napier
相关产品推荐
相关产品推荐

