文章摘要
GPT 4
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结

说在前面

上一篇我们什么都不考虑,垮垮垮写出了一个长度单位转换的小组件,但是细看用到了switch,写了很多感觉很复杂的代码,今天我们看下要怎么完善它,用上 Swift 自带的一些方法。

单位转换小组件(优化版)

1
2
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

MeasurementFormatter 是 Swift 中用于格式化 Measurement 对象的类。
Measurement 对象通常包含一个数值和一个单位。MeasurementFormatter 可以将这样的对象格式化为易于理解和阅读的字符串表示形式。
以下是 MeasurementFormatter 的一些重要属性和方法:

属性:

unitOptions :控制要显示的单位选项,例如 .providedUnit (使用提供的单位)、 .naturalScale (使用自然缩放的单位)等。
unitStyle :决定单位的显示风格,比如 .long (完整的单位名称,如 “米”)、 .short (缩写,如 “m”)、 .abbreviated (更简短的缩写)等。

方法:

string(from:) :这是主要的方法,用于将给定的 Measurement 对象转换为格式化的字符串。

使用 MeasurementFormatter 可以使单位的格式化更加灵活和准确,适应不同的需求和场景,确保单位的显示符合应用的要求和用户的期望。

进阶挑战

1
2
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 的方法,但是无奈报错,后续看看具体原因。