前言
为了更加熟悉和了解SwiftUI
,本系列将从实战角度出发完成100个SwiftUI项目,方便大家更好地学习和掌握SwiftUI
。
这同时也是对自己学习SwiftUI
过程的知识整理。
如有错误,以你为准。
项目搭建
首先,创建一个新的SwiftUI
项目,命名为UnitConversion
。
逻辑分析
样式部分我们的思路很简单,我们输入一个数字,它可以是时、分、秒,然后系统会自动输出转换后的结果。
当然,为了让App
更加灵活,我们可以设置输入的数字的单位,也可以指定输出内容的单位。
页面样式
App标题
标题部分,我们使用Text
文字作为标题,当然我们也可以使用Navigation
的方式,示例:
// 标题 func titleView() -> some View { HStack { Text("时分秒转换") .font(.title) .fontWeight(.bold) Spacer() } } 复制代码
单位转换菜单
为了让单位转换更加灵活,我们需要构建了一个转换菜单,供用户自定义转换单位。
首先先声明转换菜单的默认值,示例:
@State var beforeMenu: String = "时" @State var afterMenu: String = "秒" 复制代码
然后可以使用Menu
菜单构建转换菜单的样式,示例:
// 输入值类型 func beforeMenuView() -> some View { Menu { Button("时") { self.beforeMenu = "时" } Button("分") { self.beforeMenu = "分" } Button("秒") { self.beforeMenu = "秒" } } label: { Label(beforeMenu, systemImage: "chevron.down") .foregroundColor(.gray) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 10, maxHeight: 60) .background(Color(.systemGray6)) .cornerRadius(8) } } // 输出值类型 func afterMenuView() -> some View { Menu { Button("时") { self.afterMenu = "时" } Button("分") { self.afterMenu = "分" } Button("秒") { self.afterMenu = "秒" } } label: { Label(afterMenu, systemImage: "chevron.down") .foregroundColor(.gray) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 10, maxHeight: 60) .background(Color(.systemGray6)) .cornerRadius(8) } } 复制代码
上述代码中,我们使用Menu
构建了2个菜单,转换前菜单默认为“时”,转换后菜单默认为“秒”,而当我们点击菜单时,后重新给beforeMenu
、afterMenu
赋值,就可以达到单位菜单切换的效果。
其他样式部分我们就很简单,使用系统自带的Image
图标,做一个点击下拉的样式。整体交互如下:
数值输入框
数值输入部分,我们也需要提前声明两个变量存储转换前和转换后的值,示例:
@State var beforeText: String = "" @State var afterText: String = "0" 复制代码
另外为了展示效果,在数值输入前,我们可以声明一个变量来改变是否展示转换结果,示例:
@State var showResult: Bool = false 复制代码
然后是数值输入的样式,我们使用TextField
作为输入框,接收用户输入的数值内容,示例:
// 输入输出值 func numberView() -> some View { HStack(spacing: 20) { TextField("请输入", text: $beforeText) .keyboardType(.decimalPad) .foregroundColor(.black) .font(.system(size: 17)) .padding() Spacer() if showResult { Text("="+afterText+afterMenu) .foregroundColor(.black) .font(.system(size: 14)) .padding() } } .frame(minWidth: 0, maxWidth: .infinity, minHeight: 10, maxHeight: 120) .background(Color(.systemGray6)) .cornerRadius(8) } 复制代码
上述代码中,我们使用TextField
作为数值输入框,然后接收到的输入内容绑定到beforeText
参数,然后给TextField
设置修饰符,键盘默认为数字键盘。
对于转换后结果部分,我们在showResult
为True
时展示,内容绑定afterText
。
整体样式布局
var body: some View { VStack(spacing: 20) { titleView() HStack { beforeMenuView() afterMenuView() } numberView() Spacer() }.padding(.horizontal) } 复制代码
至此,样式部分我们就完成了。
计算方法
下面,我们来完成计算部分,计算部分也比较简单,我们知道时、分、秒的转换都是60的倍数,我们用最简单的逻辑书写公式,示例:
// 计算方法 func calculateMethod() { if beforeMenu == "时" && afterMenu == "分" { afterText = String((Double(beforeText) ?? 0) * 60) } else if beforeMenu == "时" && afterMenu == "秒" { afterText = String((Double(beforeText) ?? 0) * 3600) } else if beforeMenu == "分" && afterMenu == "秒" { afterText = String((Double(beforeText) ?? 0) * 60) } else if beforeMenu == "分" && afterMenu == "时" { afterText = String((Double(beforeText) ?? 0) / 60) } else if beforeMenu == "秒" && afterMenu == "分" { afterText = String((Double(beforeText) ?? 0) / 60) } else if beforeMenu == "秒" && afterMenu == "时" { afterText = String((Double(beforeText) ?? 0) / 3600) } else { afterText = beforeText } } 复制代码
然后将计算方法使用在我们输入值改变时,调用我们计算的方法,示例:
.onChange(of: beforeText) { _ in if beforeText != "" { self.showResult = true calculateMethod() } else { self.showResult = false } } 复制代码
完成后,我们预览下项目成果。
项目预览
不错不错!