🔋

Swift 格式化指南:如何区分显示身高与道路距离

核心速览: 在英制 Locale 下,180 cm 的桌子应显示为 5.9 ft,而人的身高应显示为 5 ft 11 in。不要手动编写单位换算逻辑,利用 MeasurementFormatStyleusage 参数(如 .personHeight),系统会自动根据语义和区域设置输出最符合当地习惯的格式。

问题

在开发国际化 App 时,开发者经常面临一个棘手的“语境”问题:同一种物理量,在不同场景下的表述习惯完全不同。

最典型的例子是长度。假设数据库中存储的数值是 180,单位是 centimeters

  • 场景 A(家具尺寸): 如果是一张桌子,美国用户习惯看到 “5.9 ft”(小数形式)。
  • 场景 B(人体身高): 如果是用户的身高,美国用户绝对期望看到 “5 ft 11 in”(混合单位),而不是怪异的 “5.9 ft”。

许多开发者为了解决这个问题,往往会编写复杂的 if-else 或手动操作 MeasurementFormatter,代码冗长且容易在边缘情况(如 1 ft 0 in 还是 1 ft)上出错。

解决方案

Swift 的 FormatStyle API 早已内置了“语义感知”能力。你不需要关心具体的数学换算,只需要通过 usage 参数告诉系统“这个数值是用来做什么的”。

系统会根据当前的 Locale 和你提供的 usage,自动做出以下决策:

  1. 单位选择:是使用公制(m/cm)还是英制(ft/in/mi)。
  2. 格式细节:是使用小数(5.9 ft)还是混合单位(5 ft 11 in)。
  3. 量级调整:对于道路距离,系统会自动根据数值大小决定显示米、千米还是英里。

代码实现

以下代码展示了如何利用 .measurement 修饰符处理不同的语义场景:

Swift
import SwiftUI

// 基础数据:180 厘米
let rawMeasurement = Measurement(value: 180, unit: UnitLength.centimeters)

struct MeasurementExample: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            
            // asProvided 180cm
            LabeledContent("asProvided", value: rawMeasurement,
                           format: .measurement(width: .abbreviated,usage: .asProvided))
                .environment(\.locale, .init(identifier: "en_US"))
            
            // Person's Height 5ft, 11in
            LabeledContent("Person Height", value: rawMeasurement,
                           format: .measurement(width: .abbreviated, usage: .personHeight))
                .environment(\.locale, .init(identifier: "en_US"))
            
            // General 5.9ft
            LabeledContent("General", value: rawMeasurement,
                           format: .measurement(width: .abbreviated, usage: .general))
                .environment(\.locale, .init(identifier: "en_US"))
        }
        .padding(30)
        .font(.title)
    }
}

注意事项

  • UI 布局的弹性personHeight 在英制环境下生成的字符串(如 “5 ft 11 in”)通常比公制(“180 cm”)更长。在设计 UI 时(尤其是列表或卡片布局),务必预留足够的水平空间,或使用 ViewThatFits 来处理潜在的文字截断。
  • 系统主导权: 当你使用 usage 参数(特别是 .road)时,你将“显示什么单位”的控制权完全交给了 Apple。对于很大的厘米数值,系统可能会直接格式化为“公里”或“英里”。如果你有硬性业务指标必须显示特定单位(例如必须显示“米”),请不要使用 usage,而应先使用 .converted(to:) 转换单位后再进行基础格式化。

延伸阅读

MeasurementFormatStyle 只是 Swift 强大的度量值处理系统的一部分。如果你想深入了解如何处理自定义单位、对比新旧 Formatter 的性能差异,或者掌握更多像 usage 这样鲜为人知但极其实用的参数,建议阅读深度解析:

相关提示

订阅 Fatbobman 周报

每周精选 Swift 与 SwiftUI 开发技巧,加入众多开发者的行列。

立即订阅