SwiftUI 是一个声明式的 UI 开发方式,在这之前我们先看看声明式和指令式开发。
指令式 & 声明式 简单了解
指令式编程:通过一些组合语句例如 运算语句、条件语句、循环语句逐条指示计算机如何工作,为了更好的理解我们来看下这个例子:
ini
struct Student {
let name: String
let score: Int
}
let zhangsan = Student(name: "zhangsan", score: 100)
let lisi = Student(name: "lisi", score: 60)
let students = [zhangsan, lisi]
我们如果想要知道分数最高的学生 如下:
var best: (Student, Int)?
for student in students {
if let tempBest = best {
if tempBest.1 < student.score {
best = (student, student.score)
} else {
best = (student, student.score)
}
}
}
那么如果我们想知道了这段代码具体是什么含义,必须要清楚的知道每一行指令具体做了什么,这样对于开发人员的要求非常高,并且代码越多隐藏的问题也会越多。
声明式开发正好和这个是对立的,声明式更像是我们要告诉计算机要做什么,例如我们平时使用的高阶函数,我们不用去关心过程,例如上述我们找到成绩最好的学生
ini
let best = students.sorted{$0.score > $1.score}.first
我们只需要知道这段代码结果是什么。
SwiftUI中,用户界面是严格被数据驱动的,在运行时,我们只能通过修改数据来修改界面,不能直接对界面进行调整和操作,下面我们会有单独文章介绍,这里我们先简单看看声明式UI
UI 都是通过 View 来呈现的,我们写个简单的 hello SwiftUI
swift
struct TestUI: View {
var body: some View {
Text("hello Swift UI")
Button("test") {
print("test")
}
}
}
这段代码是可以让我们来实时的看到UI 我们在body中修改可以实时看到效果
struct TestUI_Previews: PreviewProvider {
static var previews: some View {
TestUI()
}
}
在预览栏中我们应该可以实时看到一个界面了
UI Modifier
上述代码你是不是会想我们平时写界面会控制一些label的属性,颜色、字体颜色等,这样不得不引入到Modifier(个人比较喜欢swift的命名方式,简单、语义准确、容易理解), 下面我们通过例子来看看Modifier对text的影响
这些都是 View 的 Modifier,当然还有很多可以看官方文档,从图中可以发现,红色框中和蓝色框中的modifier 是不同的,像蓝色框里这种 font, 字体颜色对顺序要求不高,他们是对 Text 本身的属性修改,对布局也不会产生影响,但是红色框中的pading, background 是对 View 的 extension,对顺序有很高的要求,他们是对 View 进行包装并且返回的 View 的封装类, 可以对比下 橘色框和绿色框的pading。
UI 基本布局
通过上述学习我们了解到 UI 是通过 View 来呈现的,接下来通过例子我们先看看 Swift 里 View 的封装
示例需求: 布局一个 9 宫格的数字展示 从 1-9
1、先看展示部分 最简单的写法如下:
作为有追求的技术人员,一定会想抽象这段代码,恰好小编也对代码有追求的,我们先来对 Text 进行抽象成为一个通用的 view
less
struct SudokuItemLabel: View {
var fontSize: CGFloat = 30 //提供默认值
var title: String
var size: CGSize
var backGroundColor: Color
var foregroundColor: Color
var body: some View {
Text(title)
.font(.system(size: fontSize))
.foregroundColor(foregroundColor)
.background(backGroundColor)
.frame(width: size.width, height: size.height)
}
}
然后使用同样的方式对横向进行封装,既然横向是一个同样的逻辑,必然牵扯要动态使用 model 来读取数据,我们先创建一个 item 作为每个数字的数据源
arduino
enum SudokuItem {
case digit(Int)
}
extension SudokuItem: Hashable {
var title: String {
switch self {
case .digit(let value):
return String(value)
}
}
var size: CGSize {
let width = floor((UIScreen.main.bounds.size.width - 20 - 3 * 6) / 4)
if case .digit(let value) = self, value == 0 {
return CGSize(width: width * 2, height: 88)
}
return CGSize(width: width, height: 88)
}
}
在对横向 UI 进行封装如下:
less
struct SudokuItemRow: View {
let items: [SudokuItem]
var body: some View {
HStack {
ForEach(items, id:\.self) {item in
SudokuItemLabel(title: item.title, size: item.size)
}
}
}
}
再来看下ContentView的代码
是不是非常简洁了,其实封装思想、设计原则都是相同的,只不过 UI 是通过 View 来呈现。
希望这段代码可以帮助你快速的入门 SwiftUI, 更多知识可以参考官方文档
关于数据驱动 UI 变化的文章,请看我的下篇文章