之前因为是基础知识,将笔记记录得跟教程一样,其实就是方便自己日后检索这些基础知识。从今天开始将真正作为笔记来完成。愿景就是用博客创建一个知识库。

创建Xcode项目时的初始文件说明

在Xcode内部,你应该在左侧的空间中看到以下文件,这称为项目导航器:

  • AppDelegate.swift包含用于管理你的应用程序的代码。在这里添加代码曾经很常见,但是如今却很少见。
  • SceneDelegate.swift包含用于在应用程序中启动一个窗口的代码。这在iPhone上没有多大作用,但在iPad上(用户可以同时打开你的应用的多个实例),这很重要。
  • ContentView.swift包含程序的初始用户界面(UI),并且我们将在该项目中完成所有工作。
  • Assets.xcassets是资产目录 –你要在应用程序中使用的图片的集合。你还可以在此处添加颜色,以及应用程序图标,iMessage贴纸等。
  • LaunchScreen.storyboard是一个可视化编辑器,用于创建一小段UI来显示应用程序启动的时间。
  • Info.plist是一个特殊值的集合,这些特殊值向系统描述了你的应用程序的工作方式-它是哪个版本,你支持的设备方向等等。不是代码,但仍然很重要的事情。
  • 预览内容是一个黄色的组,其中包含Preview Assets.xcassets –这是另一个资产目录,这一次专门针对例如你在设计用户界面时要使用的图像,以使你了解它们在外观时的外观该程序正在运行。

恢复Xcode的预览快捷键

通常,你会发现代码中的错误使Xcode的画布无法更新-你会看到类似“自动预览更新已暂停”的信息,并可以按Resume进行修复。正如你将要做的很多一样,让我推荐一个重要的快捷方式:Option + Cmd + P与单击“恢复”相同。

创建表单

1
2
3
4
5
6
7
8
9
10
11
12
Form {
Text("Hello World")
Text("Hello World")
Text("Hello World")
Text("Hello World")
Text("Hello World")
Text("Hello World")
Text("Hello World")
Text("Hello World")
Text("Hello World")
Text("Hello World")
}

表单最多创建10条,超过10条需要用Group{}分组,如果想要离散式排布用Section{}

使用小标题的navigationBarTitle

1
.navigationBarTitle("SwiftUI", displayMode: .inline)

navigationBarTitle要放入NavigationView的花括号中

通过属性包装器@State来创建变量

Swift为我们提供了一个特殊的解决方案,称为属性包装器:可以在属性之前放置一个特殊的属性,以有效地赋予它们超能力。在存储简单的程序状态(如点击按钮的次数)的情况下,我们可以使用来自SwiftUI的名为的属性包装器@State,如下所示:

1
2
3
4
5
6
7
8
9
struct ContentView: View {
@State var tapCount = 0

var body: some View {
Button("Tap Count: \(tapCount)") {
self.tapCount += 1
}
}
}

这个小小的变化足以使我们的程序正常工作,因此你现在可以构建它并进行尝试。

@State允许我们解决结构的局限性:我们知道我们无法更改其属性,因为结构是固定的,但是@State允许SwiftUI将该值分别存储在可以修改的位置。

提示:有多种方法可以在SwiftUI中存储程序状态,你将学习所有这些方法。@State专为存储在一个视图中的简单属性而设计。因此,Apple建议我们private向这些属性添加访问控制,例如:@State private var tapCount = 0。

@state的双向绑定

用美元符号$:

1
2
3
4
5
6
7
8
9
10
struct ContentView: View {
@State private var name = ""

var body: some View {
Form {
TextField("Enter your name", text: $name)
Text("Hello World")
}
}
}

视图循环创建 ForEach

ForEach将对其循环的每个项目运行一次闭包,并传入当前循环项目。例如,如果我们从0循环到100,它将传入0,然后是1,然后是2,依此类推。

例如,这将创建一个包含100行的表单:

1
2
3
4
5
Form {
ForEach(0 ..< 100) { number in
Text("Row \(number)")
}
}

因为ForEach传入了闭包,所以我们可以对参数名称使用简写语法,如下所示:

1
2
3
4
5
Form {
ForEach(0 ..< 100) {
Text("Row \($0)")
}
}

ForEach在使用SwiftUI的Picker视图时特别有用,它使我们可以显示各种选项供用户选择。

为了说明这一点,我们将定义一个视图:

有可能的学生姓名数组。
具有@State存储当前所选学生的属性。
Picker使用对@State属性的双向绑定,创建一个视图,要求用户选择自己喜欢的视图。
用于ForEach遍历所有可能的学生姓名,将其转换为文本视图。
这是该代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ContentView: View {
let students = ["Harry", "Hermione", "Ron"]
@State private var selectedStudent = 0

var body: some View {
VStack {
Picker("Select your student", selection: $selectedStudent) {
ForEach(0 ..< students.count) {
Text(self.students[$0])
}
}
Text("You chose: Student # \(students[selectedStudent])")
}
}
}

那里没有很多代码,但是值得澄清一些事情:

  • 该students阵列不需要标明@State,因为它是一个常数; 它不会改变。
  • 该selectedStudent属性以值0开头,但可以更改,这就是为什么将其标记为的原因@State。
  • 该Picker有一个标签,“选择你的学生”,它告诉用户它做什么,并且还提供了一些描述性的屏幕阅读器大声朗读。
  • 与Picker具有双向绑定selectedStudent,这意味着它将开始显示选择0,但随着用户移动选择器而更新属性。
  • 在内部,ForEach我们从0到(但不包括)数组中的学生数量进行计数。
  • 我们为每个学生创建一个文本视图,以显示该学生的姓名。

参考资料

查看下一天的SwiftUI学习笔记

关于100days英文课程