百日学 Swift(Day 19) – 挑战:长度单位转换

百日学 Swift(Day 19) – Challenge day(挑战:长度单位转换)

根据教程要求,独立编写了长度单位转换,引入了本地数据以简化代码。将两个长度单位分别用 json 文件保存。利用结构体读取数据,形成数组。

1. 数据模型 Units.swift

import Foundation

struct LengthUnits: Hashable, Codable, Identifiable { // 混装,备用
    var id: Int
    var category: String
    var items: [LengthUnit]
}

struct LengthUnit: Hashable, Codable, Identifiable  { // 某个制式的内容
    var id: Int				// 为 0 的是基准单位
    var name: String		// 名称
    var coefficient: Double	// 与基准单位的转换系数(倍数)
}

2. json 数据文件

json 文件保存在 Resources 文件夹,是加载读取的默认路径。

分别将两种制式存入不同文档,这样既方便读取,又便于今后扩展某个制式。

(1)公制单位:MetricUnits.json

[
    {
        "id" : 0,
        "name" : "毫米",
        "coefficient" : 1.0
    },
    {
        "id" : 1,
        "name" : "厘米",
        "coefficient" : 10.0
    },
    {
        "id" : 2,
        "name" : "米",
        "coefficient" : 1000.0
    },
    {
        "id" : 3,
        "name" : "千米",
        "coefficient" : 1000000.0
    }
]

(2)英制单位:EnglishUnits.json

[
    {
        "id" : 0,
        "name" : "英寸",
        "coefficient" : 1.0
    },
    {
        "id" : 1,
        "name" : "英尺",
        "coefficient" : 12.0
    },
    {
        "id" : 2,
        "name" : "码",
        "coefficient" : 36.0
    },
    {
        "id" : 3,
        "name" : "英里",
        "coefficient" : 60120.0
    }
]

(3)混装 AllUnits.json

[
    {
        "id": 0,
        "category": "Metric",
        "items": [
            {
                "id" : 0,
                "name" : "毫米",
                "coefficient" : 1.0
            },
            {
                "id" : 1,
                "name" : "厘米",
                "coefficient" : 10.0
            },
            {
                "id" : 2,
                "name" : "米",
                "coefficient" : 1000.0
            },
            {
                "id" : 3,
                "name" : "千米",
                "coefficient" : 1000000.0
            }
        ]
    },
    {
        "id": 1,
        "category": "English",
        "items": [
            {
                "id" : 0,
                "name" : "英寸",
                "coefficient" : 1.0
            },
            {
                "id" : 1,
                "name" : "英尺",
                "coefficient" : 12.0
            },
            {
                "id" : 2,
                "name" : "码",
                "coefficient" : 36.0
            },
            {
                "id" : 3,
                "name" : "英里",
                "coefficient" : 60120.0
            }
        ]
    }
]

3. 加载数据 Data.swift

与数据模型一道保存在 Models 中,便于管理。

应用运行后,会加载全局变量,分别保存了不同制式的数组供视图使用。

import Foundation
import UIKit
import SwiftUI
import CoreLocation

let MetricUnits: [LengthUnit] = load("MetricUnits.json")
let EnglishUnits: [LengthUnit] = load("EnglishUnits.json")
let AllUnits: [LengthUnits] = load("AllUnits.json")
let temp = 0

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
        else {
            fatalError("Couldn't find \(filename) in main bundle.")
    }
    
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

4. 视图文件 ConvertUnit.swift

主要练习了以下几个方面:

  • 全局变量加载本地 json 文件
  • 表单视图的排列,Section的应用
  • 表单控件的使用,包括 TextField、Picker及其修饰器(键盘的选择、Picker的样式)
  • 巩固练习了容器组件 VStack、HStack 和 NavigationView。
  • 巩固练习了 Button、Text 等视图组件及其修饰器的使用。
  • 巩固练习了状态的使用和双向绑定。
import SwiftUI

struct ContentView: View {
    @State private var isMetricToEnglish = true
    @State private var inputString = ""
    @State private var inIndex = 0
    @State private var outIndex = 0
    
    var inArray:[LengthUnit]  { return isMetricToEnglish ? MetricUnits : EnglishUnits }
    var outArray:[LengthUnit]  { return !isMetricToEnglish ? MetricUnits : EnglishUnits }
    
    var result: Double {
        var outNumber: Double = 0
        let inCoe = inArray[inIndex].coefficient
        let outCoe = outArray[outIndex].coefficient
        let inNumber = Double(inputString) ?? 0
        let rate = isMetricToEnglish ? 1/25.4 : 25.4	// 两种制式基准单位的转换
        outNumber = inNumber * inCoe * rate / outCoe	
        return outNumber
    }
    
    var body: some View {
        
        NavigationView{
            VStack{
                Button(action: {self.isMetricToEnglish.toggle()}){
                    Text(isMetricToEnglish ? "公制 → 英制" : "英制 → 公制")
                        .font(.headline)
                }
                .frame(width: 120, height: 40)
                .foregroundColor(.white)
                .background(Color(
                    #colorLiteral(red: 0.2392156869, 		// 颜色字面量
                                  green: 0.6745098233, 
                                  blue: 0.9686274529, 
                                  alpha: 1)))
                .cornerRadius(CGFloat(10.0))
                .shadow(radius: CGFloat(15.0))
                
                Form{
                    Section(header: Text("将 \(isMetricToEnglish ? "公制" : "英制")")
                        .font(.subheadline).bold()
                    ){
                        TextField("输入\(isMetricToEnglish ? "公制" : "英制")长度", text: $inputString)
                            
                        .frame(maxWidth: .infinity)
                        .keyboardType(.decimalPad)
                            
                        Picker("", selection: $inIndex){
                            ForEach(0..<inArray.count) { index in
                                Text(self.inArray[index].name)
                            }
                        }.pickerStyle(SegmentedPickerStyle())
                    }
                    
                    Section(header: Text("转换为 \(!isMetricToEnglish ? "公制" : "英制")")
                        .font(.subheadline).bold()
                    ){
                        Text("单位")
                        Picker("", selection: $outIndex){
                            ForEach(0..<outArray.count) { index in
                                Text(self.outArray[index].name)
                            }
                        }.pickerStyle(SegmentedPickerStyle())
                    }
                    Section(header: Text("结果")
                        .font(.subheadline).bold()
                    ) {
                        Text("\(result, specifier: "%.2f")")
                    }
                }
                }.navigationBarTitle("长度转换").padding()
        }
    }
}

【项目心得】

  1. json文件的书写一定要仔细检查,系统对格式的要求超级严格。至少要使用线上工具校验一下。
  2. 拼写、拼写、拼写,在有自动提示的前提下,基本上关键字不会出错,但是自定义的变量名还是很容易错的。
  3. 阴影修饰一定要在圆角修饰之后
  4. 发现错误不用怕,慢慢找,总能查出原因的。

需要进一步研究:

  1. keyboard的呼出与隐藏,要再继续多实验几次。
  2. 修饰器还需要多熟悉
发布了77 篇原创文章 · 获赞 16 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/hh680821/article/details/105213456