携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情。
在本章中,你将学会使用SwiftUI搭建一个单位转换App。
前言
为了更加熟悉和了解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
}
}
完成后,我们预览下项目成果。
项目预览
不错不错!
如果本专栏对你有帮助,不妨点赞、评论、关注~