此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结
说在前面
上一篇我们什么都不考虑,垮垮垮写出了一个长度单位转换的小组件,但是细看用到了switch,写了很多感觉很复杂的代码,今天我们看下要怎么完善它,用上 Swift 自带的一些方法。
单位转换小组件(优化版)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 
 | import SwiftUI
 struct ContentView: View {
 @State private var input = 100.0
 @State private var inputUnit = UnitLength.meters
 @State private var outputUnit = UnitLength.kilometers
 
 @FocusState private var inputIsFocused :Bool
 
 let units: [UnitLength] = [.feet, .meters, .kilometers, .miles, .yards]
 let formatter: MeasurementFormatter
 
 var result: String {
 let inputMeasurement = Measurement(value: input, unit: inputUnit)
 let outputMeasurement = inputMeasurement.converted(to: outputUnit)
 return formatter.string(from: outputMeasurement)
 }
 
 
 var body: some View {
 NavigationStack{
 Form{
 Section("输入你要转换的值"){
 TextField("输入值",value: $input,format:.number)
 .keyboardType(.decimalPad)
 .focused($inputIsFocused)
 }
 Picker("选择你的单位",selection: $inputUnit){
 ForEach(units,id:\.self){
 Text(formatter.string(from: $0).capitalized)
 }
 }
 Picker("选择你想转换的单位",selection: $outputUnit){
 ForEach(units,id:\.self){
 Text(formatter.string(from: $0).capitalized)
 }
 }
 Section("结果"){
 Text(result)
 }
 }
 }
 .navigationTitle("转换器")
 .toolbar{
 if inputIsFocused{
 Button("完成"){
 inputIsFocused = false
 }
 }
 }
 }
 init(){
 formatter = MeasurementFormatter()
 formatter.unitOptions = .providedUnit
 formatter.unitStyle = .long
 }
 }
 
 | 
实现效果图
![转换器示例-优化版]()
可以看出 Picker 选择器下面的单位变成了英文,这是因为这里用到的是 swift 自带的一些方法,底层也支持这些单位的互相转换,汉字的话目前还没有直接可以实现的方法。
知识点
以下是这段新代码与之前代码的一些区别和新增的知识点:
区别:
- 使用了 UnitLength 类型来表示单位,而不是字符串。
- 使用 Measurement 和 MeasurementFormatter 类来进行单位转换和格式化,提供了更准确和规范的处理方式。
新增知识点:
- @FocusState :用于管理视图元素的焦点状态。
- toolbar:用于在视图顶部添加工具栏,并根据焦点状态显示 “完成” 按钮。
- 初始化方法 init :用于初始化 MeasurementFormatter 并设置其属性。
- 对单位的处理更加规范化和类型安全,利用了系统提供的相关类型和类来进行转换和展示。
MeasurementFormatter 是 Swift 中用于格式化 Measurement 对象的类。
Measurement 对象通常包含一个数值和一个单位。MeasurementFormatter 可以将这样的对象格式化为易于理解和阅读的字符串表示形式。
以下是 MeasurementFormatter 的一些重要属性和方法:
属性:
unitOptions :控制要显示的单位选项,例如 .providedUnit (使用提供的单位)、 .naturalScale (使用自然缩放的单位)等。
unitStyle :决定单位的显示风格,比如 .long (完整的单位名称,如 “米”)、 .short (缩写,如 “m”)、 .abbreviated (更简短的缩写)等。
方法:
string(from:) :这是主要的方法,用于将给定的 Measurement 对象转换为格式化的字符串。
使用 MeasurementFormatter 可以使单位的格式化更加灵活和准确,适应不同的需求和场景,确保单位的显示符合应用的要求和用户的期望。
进阶挑战
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 
 | import SwiftUI
 struct ContentView: View {
 @State private var input = 100.0
 @State private var inputUnit: Dimension = UnitLength.meters
 @State private var outputUnit: Dimension = UnitLength.kilometers
 @State private var selectedUnits = 0
 
 @FocusState private var inputIsFocused :Bool
 
 let conversions = ["距离","质量","温度","时间"]
 
 let unitTypes = [
 [UnitLength.feet, UnitLength.meters, UnitLength.kilometers, UnitLength.miles, UnitLength.yards],
 [UnitMass.grams, UnitMass.kilograms, UnitMass.ounces, UnitMass.pounds],
 [UnitTemperature.celsius, UnitTemperature.fahrenheit, UnitTemperature.kelvin],
 [UnitDuration.hours, UnitDuration.minutes, UnitDuration.seconds]
 ]
 let formatter: MeasurementFormatter
 
 var result: String {
 let inputMeasurement = Measurement(value: input, unit: inputUnit)
 let outputMeasurement = inputMeasurement.converted(to: outputUnit)
 return formatter.string(from: outputMeasurement)
 }
 
 
 var body: some View {
 NavigationStack{
 Form{
 Section("输入你要转换的值"){
 TextField("输入值",value: $input,format:.number)
 .keyboardType(.decimalPad)
 .focused($inputIsFocused)
 }
 Picker("转换类型",selection: $selectedUnits){
 ForEach(0..<conversions.count, id:\.self){
 Text(conversions[$0])
 }
 }
 
 Picker("选择你的单位",selection: $inputUnit){
 ForEach(unitTypes[selectedUnits],id:\.self){
 Text(formatter.string(from: $0).capitalized)
 }
 }
 Picker("选择你想转换的单位",selection: $outputUnit){
 ForEach(unitTypes[selectedUnits],id:\.self){
 Text(formatter.string(from: $0).capitalized)
 }
 }
 Section("结果"){
 Text(result)
 }
 }
 .navigationTitle("转换器")
 .toolbar {
 if inputIsFocused{
 Button("完成"){
 inputIsFocused = false
 }
 }
 }
 }
 }
 
 init(){
 formatter = MeasurementFormatter()
 formatter.unitOptions = .providedUnit
 formatter.unitStyle = .long
 }
 }
 
 | 
实现效果图
![进阶版转换器-增加转换类型]()
![进阶版转换器-质量转换效果]()
可以看到我们实现了多种单位的转化。
说在后面
找bug:
- 发现之前 .navigationTitle 和 .toolbar 的方法位置错误了,造成效果一直没出来。
- 示例里还有一个给 .toolbar 下继续添加 .onChange 的方法,但是无奈报错,后续看看具体原因。