You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中Text/TextField的Measurement本地化与单位切换问题

解决SwiftUI中Measurement在TextField的本地化与单位切换问题

一、TextField的本地化适配

直接绑定$length.value只能拿到原始单位的数值,无法自动适配系统区域。要实现本地化的显示与输入,需通过MeasurementFormatter完成字符串与Measurement的双向转换:

  1. 定义SwiftData模型(示例):
import SwiftData
import Foundation

@Model
class LengthRecord {
    var length: Measurement<UnitLength>
    
    init(length: Measurement<UnitLength> = .init(value: 0, unit: .centimeters)) {
        self.length = length
    }
}
  1. 在View中处理TextField绑定逻辑:
import SwiftUI
import Foundation

struct LengthView: View {
    @Bindable var record: LengthRecord
    @State private var displayText = ""
    private let formatter: MeasurementFormatter = {
        let f = MeasurementFormatter()
        f.unitStyle = .medium // 可选.long/.short/.medium,控制单位显示样式
        f.locale = Locale.current // 自动跟随系统区域设置
        return f
    }()
    
    var body: some View {
        VStack(spacing: 20) {
            TextField("输入长度", text: $displayText)
                .textFieldStyle(.roundedBorder)
                .onAppear {
                    // 初始化时将Measurement转成本地化字符串
                    displayText = formatter.string(from: record.length)
                }
                .onChange(of: record.length) { _, newValue in
                    // 原始Measurement变化时同步显示文本
                    displayText = formatter.string(from: newValue)
                }
                .onChange(of: displayText) { _, newValue in
                    // 解析输入的本地化字符串,转回Measurement
                    if let parsedLength = formatter.measurement(from: newValue) {
                        record.length = parsedLength
                    }
                }
            
            // 用Text验证本地化效果
            Text("当前长度:\(record.length.formatted())")
        }
        .padding()
    }
}

核心逻辑是借助MeasurementFormatter:显示时将Measurement转换为对应区域的字符串(比如美国区域会自动显示英寸/英尺);输入时将用户输入的本地化字符串解析回Measurement,同步更新到SwiftData属性中。

二、用Picker切换长度单位

实现单位切换只需提供可选单位列表,用户选择后将当前Measurement转换为选中单位即可:

  1. 在View中添加单位Picker:
// 继续在LengthView中扩展
@State private var selectedUnit: UnitLength = .centimeters

var body: some View {
    VStack(spacing: 20) {
        // 上述TextField和Text组件
        
        Picker("选择单位", selection: $selectedUnit) {
            Text("厘米").tag(UnitLength.centimeters)
            Text("米").tag(UnitLength.meters)
            Text("英寸").tag(UnitLength.inches)
            Text("英尺").tag(UnitLength.feet)
        }
        .pickerStyle(.segmented)
        .onChange(of: selectedUnit) { _, newUnit in
            // 将当前长度转换为选中的单位
            record.length = record.length.converted(to: newUnit)
        }
        .onAppear {
            // 初始化选中单位为当前Measurement的单位
            selectedUnit = record.length.unit
        }
    }
    .padding()
}

用户切换Picker选项时,record.length会自动转换为选中单位,同时TextField的显示文本会因record.length的变化,自动更新为对应单位的本地化字符串。

注意事项

  • MeasurementFormatter默认跟随系统区域,模拟器切换到美国区域时,输入英寸/英尺会被正确解析。若需固定区域,可设置formatter.locale = Locale(identifier: "en_US")强制指定。
  • 解析输入时可添加无效输入的处理逻辑(比如弹出提示),上述代码中无法解析的输入会被忽略。

内容的提问来源于stack exchange,提问作者0x1801ce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:27:32