第2章:规划一个分页的应用程序¶
在本书的第1节中,你将建立一个应用程序来帮助你进行高强度的间歇训练。即使你已经在使用Apple Fitness+
或许多锻炼应用程序中的一个,也可以通过这些章节来学习如何使用Xcode
、Swift
和SwiftUI
来开发一个iOS
应用程序。
在这一章中,你将计划你的应用程序,然后设置分页界面。您将开始使用SwiftUI
属性检查器来添加修改器。在接下来的两章中,你将学习更多的Swift
和SwiftUI
来布置你的应用程序的视图,创建你的应用程序的
制作列表:视图和行动¶
这个应用程序有几个屏幕。下面是一个样本,向你展示你完成后的应用程序的样子。
这些屏幕上有很多事情,特别是有锻炼视频的那一个。你可能会感到不知所措,不知道该从哪里开始。好吧,你听说过"分而治之"这句话,这就是解决构建应用程序问题的最佳方法。
首先,你需要清点一下你要划分的内容。最顶层的划分是用户看到的东西和应用程序做的东西。许多开发者从布置屏幕开始,通常是在一个设计或原型应用程序中,让他们表明基本功能。例如,当用户点击这个按钮时,应用程序会显示这个屏幕。你可以向客户或潜在用户展示一个原型,看看他们是否理解你的应用程序的控制和功能。例如,如果他们点击标签以为是按钮,你应该重新考虑标签的设计,或者把它们实现为按钮。
列出你的用户看到的东西¶
首先,列出你需要创建的屏幕并描述其内容:
- 一个带有文字、图像和一个按钮的欢迎屏幕。
- 标题和页码在
Welcome
屏幕的顶部,History
按钮在底部。这些也都在练习视频的屏幕上。页码表示在这一页之后还有四个编号的页面。挥舞的手的符号被突出显示。 - 练习视频的屏幕上也有一个计时器,一个
Start/Done
按钮和评级符号。其中一个页码被突出显示。 History
屏幕以列表和柱状图的形式显示用户的练习历史。它有一个标题,但没有页码,也没有History
按钮。High Five!
屏幕有一个图像,一些大的文字和一些小的灰色文字。与History
屏幕一样,它没有页码,也没有History
按钮。
在本章和下一章中,你将布置这些屏幕的基本元素。在第10章"完善你的应用程序"中,你将对外观进行微调,使其看起来像上面的屏幕截图。
列出你的应用程序的功能¶
接下来,列出每个屏幕的功能,从最后两个开始。
History
和High Five!
屏幕是模版,在Welcome
或Exercise
的屏幕上滑起来。每个屏幕都有一个按钮,用户可以点击它来解散它,要么是一个圈起来的X
,要么是一个Continue
按钮。- 在
Welcome
和Exercise
屏幕上,匹配的页码是黑色背景上的白色文字或轮廓。点击History
按钮会显示History
屏幕。 Welcome
页的Get Started
按钮显示下一页。- 在
Exercise
页面上,用户可以点击播放按钮来播放练习的视频。 - 在
Exercise
页面上,点击Start
按钮会启动一个倒计时,按钮的标签会变成Done
。理想情况下,Start
按钮是禁用的,直到计时器达到0。点击Start
会将这个练习添加到用户当天的历史中。 - 在
Exercise
页面上,点击五个评级符号中的一个,可以改变该符号和前面所有符号的颜色。 - 在最后一个练习上点选
Done
,会显示High Five!
屏幕。 - 不错的选择。点击一个页码就可以进入该页。在
Exercise
页上点击Done
可进入下一个Exercise
页。关闭High Five!
屏幕,返回到Welcome
页。
你将在第六章"为你的应用程序添加功能"中实现所有这些功能。
还有HIITFit
的基于页面的总体结构。这在SwiftUI
中很容易实现,所以你将在创建任何屏幕之前先做这个。
创建页面¶
本节将学习的技能:向现有项目添加Git
仓库;SwiftUI
视图的可视化编辑;使用弹出式属性检查器;TabView
样式。
本节的主要目的是设置HIITFit
的基于页面的结构,但你也会学到很多关于使用Xcode
、Swift
和SwiftUI
的知识。每一节开头的技能的简短列表可以帮助你追踪到什么地方。
将源码控制添加到一个现有的项目中¶
在第1章"检查你的工具"中,你创建了一个新项目。但HIITFit
有一个带有一些资产和实用代码的启动项目。你要向这个启动项目添加文件和代码。
➤ 在Finder
中打开本章的starter
文件夹,找到HIITFit/HIITFit.xcodeproj
。双击-此文件,在Xcode
中打开它。
这个项目没有一个Git
仓库。你可以使用git init
命令行,但Xcode
提供了一个快速的方法。
➤ 在Xcode
菜单中,选择Source Control ▸ New Git Repositories
...。
出现一个窗口,选中你的项目。
➤ 点击创建。
现在,当你修改或添加文件时,你会看到标记,而且你可以在构建这个应用时提交每一个主要的添加内容。我建议先进行几次提交,然后由你来确保在进行新任务之前提交一个工作副本。
画布和编辑器始终保持同步¶
你即将体验到SwiftUI
的最佳功能之一。编辑画布的同时也在编辑代码,反之亦然!
这是你的第一个SwiftUI
词汇。你在设备屏幕上看到的所有东西都是一个视图,较大的视图包含子视图。
你的下一个SwiftUI
术语是修改器。SwiftUI
有大量的方法,你可以用来修改视图的外观或行为。
➤ 首先,在ContentView.swift
中,从body
闭包中删除.padding()
:这是一个修改器,在Text
视图周围添加空间,你现在不需要它。
➤ 在画布中,如果没有看到ContentView
就点击Resume
,然后双击Text
视图。你已经在代码中选择了Hello world
:
➤ 现在输入欢迎:你已经改变了画布和代码中的文本。
Xcode
在输入Welcome
后,不要按回车键。如果有必要,刷新预览。
Text
视图只是显示一串字符。它对于列出你计划创建的视图很有用,就像一种大纲一样。现在你将使用多个Text
视图,以了解如何实现分页行为。
➤ 在Text
视图之外的任何地方单击,取消选择Welcome
,然后再次选择Text
视图。按Command-D
:
正如你可能预料的那样,你已经重复了Text
视图。但请看代码:
VStack {
Text("Welcome")
Text("Welcome")
}
你的两个Text
视图现在被嵌入到一个VStack
中! 当你有一个以上的视图时,你必须指定如何在画布上安排它们。Xcode
知道这一点,所以它提供了默认的安排,即在一个垂直的堆栈中显示两个Text
视图。
➤ 将V
改为H
,可以看到两个视图以水平堆叠的方式显示:
➤ 键入Command-Z
来撤销此更改。SwiftUI
的默认值往往与大多数人想做的事情相吻合。
➤ 将第二个Welcome
改为Exercise 1
。然后重复Exercise 1
,将第三个字符串改为Exercise 2
。
现在你有三种不同的视图可以在TabView
中使用。
使用TabView¶
下面是创建一个TabView
的简单方法。
➤ 将VStack
改为TabView
:
你的练习去哪里了!?嗯,它们现在是标签视图的第二和第三标签,屏幕底部有一个标签栏。它是空白的,因为你还没有给标签贴上标签。
这里是你如何标记标签的。实际上,这样做非常快,但看起来很费劲,因为你将学习如何使用SwiftUI
属性检查器。
➤ 在画布或编辑器中,用Control-Option
单击Welcome``Text
视图,弹出其属性检查器。
Swift
show-inspectors
按钮(右上角的工具栏)打开右侧的面板。属性检查器是这个面板中最右边的标签。如果你在一个小的屏幕上工作,并且只想编辑一个属性,Control-Option-click
一个视图来使用弹出的检查器。它使用的空间较小。
➤ 在添加修饰符字段中单击,然后输入选项卡,并从菜单中选择选项卡项目:
一个新的tabItem
修改器出现在编辑器中,有一个项目标签的占位符:
Text("Welcome")
.tabItem { Item Label }
并在标签栏中出现一个蓝色的标签:
➤ 选择项目标签占位符并输入Text("Welcome")
:
.tabItem { Text("Welcome") }
它就在标签栏里:
➤ 用以下内容替换整个TabView
,以添加其他标签的标签:
TabView {
Text("Welcome")
.tabItem { Text("Welcome") }
Text("Exercise 1")
.tabItem { Text("Exercise 1") }
Text("Exercise 2")
.tabItem { Text("Exercise 2") }
}
现在你可以看到三个标签:
画布预览是获得视图外观持续反馈的好方法,但是,在这一点上,你可能想看到它的实际效果。这就是实时预览可以帮助的地方。
➤ 单击实时预览按钮,看看这在设备上是如何工作的:
第一次需要一些时间,但随后的实时预览会刷新得更快。如果出现恢复按钮,请点击它或按Option-Command-P
。
现在,点击一个选项卡标签来切换到该选项卡。这就是标签视图通常的操作方式。要使标签的行为像页面一样,请将此修改器添加到TableView
中:
.tabViewStyle(PageTabViewStyle())
现在你的标签不见了!
页面风格使用小的索引点,但它们是白底的,所以你看不到它们。
➤ 为了使它们显示出来,在tabViewStyle
下面添加这个修改器:
.indexViewStyle(
PageIndexViewStyle(backgroundDisplayMode: .always))
现在你可以看到索引点了:
➤ 查看实时预览:只要向左或向右滑动,每个页面就会卡住。
➤ 你不会在这个应用中使用tabItem
标签,所以要删除它们。这就是TabView
闭包内的所有代码:
TabView {
Text("Welcome")
Text("Exercise 1")
Text("Exercise 2")
}
好了,你已经设置了分页行为,但你希望这些页面是实际的Welcome
和Exercise
视图,而不仅仅是文本。为了使你的代码有条理并易于阅读,你将在自己的文件中创建每个视图,并将所有的视图文件放在一个文件夹中。
分组文件¶
本节将学习的技能:创建和分组项目文件
你即将通过组合较小的子视图来创建Welcome
和Exercise
子视图。SwiftUI
鼓励你创建可重复使用的子视图,这与你创建函数的原因相同。不要重复自己的工作。即使你不重复使用一个子视图,它也会使你的代码更容易阅读。而且,SwiftUI
将子视图编译成高效的机器代码,因此您可以创建您需要的所有子视图,而不必担心性能问题。
➤ 在项目导航器中选择ContentView.swift
。创建一个名为WelcomeView.swift
的新SwiftUI
视图文件。然后,创建另一个新的SwiftUI
视图文件,名为ExerciseView.swift
。
你的项目导航器现在包含三个视图文件:
你会再创建几个视图文件,所以现在你要用这三个文件创建一个组文件夹,并命名为Views
。
➤ 选择这三个视图文件,然后右键单击并选择从选择New Group from Selection
:
➤ 命名组Views。
组文件夹只是帮助你组织项目中的所有文件。在第5章,"组织您的应用程序的数据 "中,您将为您的应用程序的数据模型创建一个文件夹。
传递参数¶
本节将学习的技能:default initializers
;Array
;let
, var
, Int
;错误信息中的修复按钮;自动完成中的占位符
➤ 回到ContentView
中,用你的新视图替换前两个Text
占位符:
TabView {
WelcomeView() // was Text("Welcome")
ExerciseView() // was Text("Exercise 1")
Text("Exercise 2")
}
Swift
View
是一个结构体,在Swift
代码中被简称为struct
。像一个类一样,它是一个复杂的数据类型,封装了属性和方法。如果一个View
没有未初始化的属性,你可以用它的默认初始化器创建一个实例。例如,WelcomeView()
创建一个WelcomeView
的实例。
现在呢?你的应用程序将使用ExerciseView
来显示几个不同练习的名称和视频,所以你需要一个方法来索引这些数据,并将每个索引传递给ExerciseView
。
实际上,首先你需要一些练习的样本数据。在Videos文件夹中,你会发现四个视频:
Note
如果你喜欢使用你自己的视频,把它们从Finder
拖到项目导航器中。一定要选中添加到目标复选框。
➤ 在第5章"组织你的应用程序的数据"中,你将创建一个Exercise
数据类型,但对于这个原型,在ExerciseView.swift
中,只需在ExerciseView
的顶部创建两个数组,就在var body
上方:
let videoNames = ["squat", "step-up", "burpee", "sun-salute"]
let exerciseNames = ["Squat", "Step Up", "Burpee", "Sun Salute"]
Swift
数组是一个结构实例或类对象的有序集合。数组中的所有实例或对象都是同一类型。
视频名称与视频文件的名称一致。练习名称对用户来说是可见的,所以要使用标题大写和空格。
➤ 还是在ExerciseView
里面,在var body
属性上面,添加这个属性:
let index: Int
Swift
Swift
区分了用let
创建常量和用var
创建变量。
Xcode
现在抱怨previews
中的ExerciseView()
,因为它缺少index
参数。
➤ 单击红色错误图标以显示更多信息:
Xcode
经常建议一个或多个方法来修复一个错误。很多时候,它的建议是正确的,这就是其中之一。
➤ 点击修复,让Xcode
填入index
参数。
➤ 现在有一个index
值的占位符 - 一个灰色的Int
。点击它,使其变成蓝色,然后输入0
。所以现在你有了这行代码:
ExerciseView(index: 0)
Swift
像其他C
语言的后代一样,Swift
数组从0
开始计数,而不是1
。
现在使用你的index
属性来显示每个练习的正确名称。
➤ 将Hello, World!
改为此index
值的练习名称。
Text(exerciseNames[index])
回到ContentView.swift
中,Xcode
也在抱怨ExerciseView()
中缺少index
参数。
➤ 用你在ExerciseView.swift
中的同样方法来修复这个错误。
现在有一个占位符,用来表示index
值。你应该在这里输入什么?
循环¶
本节将学习的技能:ForEach
, Range
与ClosedRange
;开发者文档;带参数的初始化器
好吧, 你可以传递第一个数组索引:
ExerciseView(index: 0)
然后复制-粘贴和编辑,指定其他三个练习,但有一个更好的方法。你可能迫不及待地想使用一个循环。下面是你如何挠这个痒痒的。]
➤ 用这段代码替换TabView
中的第二和第三行:
ForEach(0 ..< 4) { index in
ExerciseView(index: index)
}
ForEach
在0
到4
的范围内循环,但由于<
符号的存在,不包括4
。每个整数值0
、1
、2
和3
都会创建一个index
值的ExerciseView
。本地变量的名称index
由你决定。你可以写这样的代码代替:
ForEach(0 ..< 4) { number in
ExerciseView(index: number)
}
开发者文档¶
➤ 这是一个很好的机会来检查Xcode
的内置文档。按住Option
键,然后点击..<
。
您正在查看Xcode
弹出的半开范围运算符的快速帮助。您也可以在快速帮助检查器中查看这些信息。
➤ 现在选择点击ForEach
:
➤ 这里的信息不多。单击在开发人员文档中打开以查看更详细的信息。
创建一个视图集合的主题包含三个初始化器。第一个是你用来在数组索引上循环的那个。
init(Range<Int>, content: (Int) -> Content)
➤ 这个ForEach
初始化器需要Range<Int>
。点击这一行,打开init(_:content:)
页面,然后点击其声明中的Range
,打开Range
页面。果然,Range
是"从一个下限到但不包括一个上限的半开区间",这与你看到的快速帮助中的..<
相匹配。
➤ 关闭文档窗口。
➤ 你将不需要TabView
的索引点。打开ContentView.swift
并更改:
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(
PageIndexViewStyle(backgroundDisplayMode: .always))
为:
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
现在,你将永远不会显示索引点了。
这是一个很好的地方,可以提交你对你的项目所做的修改,并写上提交信息,如"设置分页标签视图"。
Xcode
要提交修改到你的本地Git
仓库,选择Source Control ▸ Commit...
或按Option-Command-C
。如果有要求,请检查所有更改的文件。输入一个提交信息,然后点击提交。
你仍然在ContentView
中,所以可以实时预览你的应用程序。从一个页面扫到下一个页面,看看不同的练习名称。
关键点¶
- 通过列出用户将看到什么和应用程序将做什么来规划你的应用程序。
- 用视图和子视图构建你的应用程序,用修改器进行自定义。
- 画布和代码编辑器始终是同步的。你在其中一个中所作的修改也会出现在另一个中。
- 在
VStack
中垂直布置多个视图,或在HStack
中水平布置。 - 属性检查器帮助你修改一个视图或预览。
ForEach
让你在一个半开的数字范围内循环。TabView
可以表现得像一个标签视图或像一个页面控制器。- 你可以在画布上预览或实时预览你的视图。
从这里开始,该往哪里走?¶
你已经学习了很多关于Xcode
、Swift
和SwiftUI
的知识,只是为了创建你的应用程序的分页界面。带着你的用户看到的清单,你将在接下来的两章中创建HIITFit
原型的视图。