跳转至

第2章:规划一个分页的应用程序

在本书的第1节中,你将建立一个应用程序来帮助你进行高强度的间歇训练。即使你已经在使用Apple Fitness+或许多锻炼应用程序中的一个,也可以通过这些章节来学习如何使用XcodeSwiftSwiftUI来开发一个iOS应用程序。

在这一章中,你将计划你的应用程序,然后设置分页界面。您将开始使用SwiftUI属性检查器来添加修改器。在接下来的两章中,你将学习更多的SwiftSwiftUI来布置你的应用程序的视图,创建你的应用程序的

制作列表:视图和行动

这个应用程序有几个屏幕。下面是一个样本,向你展示你完成后的应用程序的样子。

HIITFit screens

这些屏幕上有很多事情,特别是有锻炼视频的那一个。你可能会感到不知所措,不知道该从哪里开始。好吧,你听说过"分而治之"这句话,这就是解决构建应用程序问题的最佳方法。

首先,你需要清点一下你要划分的内容。最顶层的划分是用户看到的东西和应用程序做的东西。许多开发者从布置屏幕开始,通常是在一个设计或原型应用程序中,让他们表明基本功能。例如,当用户点击这个按钮时,应用程序会显示这个屏幕。你可以向客户或潜在用户展示一个原型,看看他们是否理解你的应用程序的控制和功能。例如,如果他们点击标签以为是按钮,你应该重新考虑标签的设计,或者把它们实现为按钮。

列出你的用户看到的东西

首先,列出你需要创建的屏幕并描述其内容:

  • 一个带有文字、图像和一个按钮的欢迎屏幕。
  • 标题和页码在Welcome屏幕的顶部,History按钮在底部。这些也都在练习视频的屏幕上。页码表示在这一页之后还有四个编号的页面。挥舞的手的符号被突出显示。
  • 练习视频的屏幕上也有一个计时器,一个Start/Done按钮和评级符号。其中一个页码被突出显示。
  • History屏幕以列表和柱状图的形式显示用户的练习历史。它有一个标题,但没有页码,也没有History按钮。
  • High Five!屏幕有一个图像,一些大的文字和一些小的灰色文字。与History屏幕一样,它没有页码,也没有History按钮。

在本章和下一章中,你将布置这些屏幕的基本元素。在第10章"完善你的应用程序"中,你将对外观进行微调,使其看起来像上面的屏幕截图。

列出你的应用程序的功能

接下来,列出每个屏幕的功能,从最后两个开始。

  • HistoryHigh Five!屏幕是模版,在WelcomeExercise的屏幕上滑起来。每个屏幕都有一个按钮,用户可以点击它来解散它,要么是一个圈起来的X,要么是一个Continue按钮。
  • WelcomeExercise屏幕上,匹配的页码是黑色背景上的白色文字或轮廓。点击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的基于页面的结构,但你也会学到很多关于使用XcodeSwiftSwiftUI的知识。每一节开头的技能的简短列表可以帮助你追踪到什么地方。

将源码控制添加到一个现有的项目中

在第1章"检查你的工具"中,你创建了一个新项目。但HIITFit有一个带有一些资产和实用代码的启动项目。你要向这个启动项目添加文件和代码。

➤ 在Finder中打开本章的starter文件夹,找到HIITFit/HIITFit.xcodeproj。双击-此文件,在Xcode中打开它。

这个项目没有一个Git仓库。你可以使用git init命令行,但Xcode提供了一个快速的方法。

➤ 在Xcode菜单中,选择Source Control ▸ New Git Repositories...。

Xcode’s Source Control menu

出现一个窗口,选中你的项目。

Create a Git repository.

➤ 点击创建。

现在,当你修改或添加文件时,你会看到标记,而且你可以在构建这个应用时提交每一个主要的添加内容。我建议先进行几次提交,然后由你来确保在进行新任务之前提交一个工作副本。

画布和编辑器始终保持同步

你即将体验到SwiftUI的最佳功能之一。编辑画布的同时也在编辑代码,反之亦然!

这是你的第一个SwiftUI词汇。你在设备屏幕上看到的所有东西都是一个视图,较大的视图包含子视图。

你的下一个SwiftUI术语是修改器。SwiftUI有大量的方法,你可以用来修改视图的外观或行为。

➤ 首先,在ContentView.swift中,从body闭包中删除.padding():这是一个修改器,在Text视图周围添加空间,你现在不需要它。

➤ 在画布中,如果没有看到ContentView就点击Resume,然后双击Text视图。你已经在代码中选择了Hello world

Double-click in canvas selects text in code editor.

➤ 现在输入欢迎:你已经改变了画布和代码中的文本。

Editing code changes the view in the canvas.

Xcode

在输入Welcome后,不要按回车键。如果有必要,刷新预览。

Text视图只是显示一串字符。它对于列出你计划创建的视图很有用,就像一种大纲一样。现在你将使用多个Text视图,以了解如何实现分页行为。

➤ 在Text视图之外的任何地方单击,取消选择Welcome,然后再次选择Text视图。按Command-D

Command-D duplicates a view.

正如你可能预料的那样,你已经重复了Text视图。但请看代码:

VStack {
  Text("Welcome")
  Text("Welcome")
}

你的两个Text视图现在被嵌入到一个VStack中! 当你有一个以上的视图时,你必须指定如何在画布上安排它们。Xcode知道这一点,所以它提供了默认的安排,即在一个垂直的堆栈中显示两个Text视图。

➤ 将V改为H,可以看到两个视图以水平堆叠的方式显示:

HStack stacks its views horizontally.

➤ 键入Command-Z来撤销此更改。SwiftUI的默认值往往与大多数人想做的事情相吻合。

➤ 将第二个Welcome改为Exercise 1。然后重复Exercise 1,将第三个字符串改为Exercise 2

Three Text views in a VStack

现在你有三种不同的视图可以在TabView中使用。

使用TabView

下面是创建一个TabView的简单方法。

➤ 将VStack改为TabView

A TabView has a tab bar.

你的练习去哪里了!?嗯,它们现在是标签视图的第二和第三标签,屏幕底部有一个标签栏。它是空白的,因为你还没有给标签贴上标签。

这里是你如何标记标签的。实际上,这样做非常快,但看起来很费劲,因为你将学习如何使用SwiftUI属性检查器。

➤ 在画布或编辑器中,用Control-Option单击Welcome``Text视图,弹出其属性检查器。

Control-Option-Click to show the Attributes inspector.

Swift

show-inspectors按钮(右上角的工具栏)打开右侧的面板。属性检查器是这个面板中最右边的标签。如果你在一个小的屏幕上工作,并且只想编辑一个属性,Control-Option-click一个视图来使用弹出的检查器。它使用的空间较小。

➤ 在添加修饰符字段中单击,然后输入选项卡,并从菜单中选择选项卡项目:

Select the Tab Item modifier.

一个新的tabItem修改器出现在编辑器中,有一个项目标签的占位符:

Text("Welcome")
  .tabItem { Item Label }

并在标签栏中出现一个蓝色的标签:

A tab item with default label

➤ 选择项目标签占位符并输入Text("Welcome")

.tabItem { Text("Welcome") }

它就在标签栏里:

Result of replacing the placeholder tab item label

➤ 用以下内容替换整个TabView,以添加其他标签的标签:

TabView {
  Text("Welcome")
    .tabItem { Text("Welcome") }
  Text("Exercise 1")
    .tabItem { Text("Exercise 1") }
  Text("Exercise 2")
    .tabItem { Text("Exercise 2") }
}

现在你可以看到三个标签:

Three tab items with labels

画布预览是获得视图外观持续反馈的好方法,但是,在这一点上,你可能想看到它的实际效果。这就是实时预览可以帮助的地方。

➤ 单击实时预览按钮,看看这在设备上是如何工作的:

The Live Preview button

第一次需要一些时间,但随后的实时预览会刷新得更快。如果出现恢复按钮,请点击它或按Option-Command-P

现在,点击一个选项卡标签来切换到该选项卡。这就是标签视图通常的操作方式。要使标签的行为像页面一样,请将此修改器添加到TableView中:

.tabViewStyle(PageTabViewStyle())

现在你的标签不见了!

页面风格使用小的索引点,但它们是白底的,所以你看不到它们。

➤ 为了使它们显示出来,在tabViewStyle下面添加这个修改器:

.indexViewStyle(
  PageIndexViewStyle(backgroundDisplayMode: .always))

现在你可以看到索引点了:

TabView page style index dots

➤ 查看实时预览:只要向左或向右滑动,每个页面就会卡住。

Live Preview: TabView page style in mid-swipe

➤ 你不会在这个应用中使用tabItem标签,所以要删除它们。这就是TabView闭包内的所有代码:

TabView {
  Text("Welcome")
  Text("Exercise 1")
  Text("Exercise 2")
}

好了,你已经设置了分页行为,但你希望这些页面是实际的WelcomeExercise视图,而不仅仅是文本。为了使你的代码有条理并易于阅读,你将在自己的文件中创建每个视图,并将所有的视图文件放在一个文件夹中。

分组文件

本节将学习的技能:创建和分组项目文件

你即将通过组合较小的子视图来创建WelcomeExercise子视图。SwiftUI鼓励你创建可重复使用的子视图,这与你创建函数的原因相同。不要重复自己的工作。即使你不重复使用一个子视图,它也会使你的代码更容易阅读。而且,SwiftUI将子视图编译成高效的机器代码,因此您可以创建您需要的所有子视图,而不必担心性能问题。

➤ 在项目导航器中选择ContentView.swift。创建一个名为WelcomeView.swift的新SwiftUI视图文件。然后,创建另一个新的SwiftUI视图文件,名为ExerciseView.swift

你的项目导航器现在包含三个视图文件:

Project navigator after you add two SwiftUI view files

你会再创建几个视图文件,所以现在你要用这三个文件创建一个组文件夹,并命名为Views

➤ 选择这三个视图文件,然后右键单击并选择从选择New Group from Selection

Create a group folder containing the three view files.

➤ 命名组Views。

组文件夹只是帮助你组织项目中的所有文件。在第5章,"组织您的应用程序的数据 "中,您将为您的应用程序的数据模型创建一个文件夹。

传递参数

本节将学习的技能:default initializersArraylet, 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文件夹中,你会发现四个视频:

One of the exercise videos

Note

如果你喜欢使用你自己的视频,把它们从Finder拖到项目导航器中。一定要选中添加到目标复选框。

If you add your own videos, check Add to targets.

➤ 在第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参数。

➤ 单击红色错误图标以显示更多信息:

Open the error to show the Fix button.

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参数。

Another error to fix

➤ 用你在ExerciseView.swift中的同样方法来修复这个错误。

现在有一个占位符,用来表示index值。你应该在这里输入什么?

循环

本节将学习的技能:ForEach, RangeClosedRange;开发者文档;带参数的初始化器

好吧, 你可以传递第一个数组索引:

ExerciseView(index: 0)

然后复制-粘贴和编辑,指定其他三个练习,但有一个更好的方法。你可能迫不及待地想使用一个循环。下面是你如何挠这个痒痒的。]

➤ 用这段代码替换TabView中的第二和第三行:

ForEach(0 ..< 4) { index in
  ExerciseView(index: index)
}

ForEach04的范围内循环,但由于<符号的存在,不包括4。每个整数值0123都会创建一个index值的ExerciseView。本地变量的名称index由你决定。你可以写这样的代码代替:

ForEach(0 ..< 4) { number in
  ExerciseView(index: number)
}

开发者文档

➤ 这是一个很好的机会来检查Xcode的内置文档。按住Option键,然后点击..<

Option-click the ..< operator.

您正在查看Xcode弹出的半开范围运算符的快速帮助。您也可以在快速帮助检查器中查看这些信息。

➤ 现在选择点击ForEach

Quick Help for ForEach

➤ 这里的信息不多。单击在开发人员文档中打开以查看更详细的信息。

Developer Documentation for ForEach: Three initializers

创建一个视图集合的主题包含三个初始化器。第一个是你用来在数组索引上循环的那个。

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中,所以可以实时预览你的应用程序。从一个页面扫到下一个页面,看看不同的练习名称。

HIITFit pages

关键点

  • 通过列出用户将看到什么和应用程序将做什么来规划你的应用程序。
  • 用视图和子视图构建你的应用程序,用修改器进行自定义。
  • 画布和代码编辑器始终是同步的。你在其中一个中所作的修改也会出现在另一个中。
  • VStack中垂直布置多个视图,或在HStack中水平布置。
  • 属性检查器帮助你修改一个视图或预览。
  • ForEach让你在一个半开的数字范围内循环。
  • TabView可以表现得像一个标签视图或像一个页面控制器。
  • 你可以在画布上预览或实时预览你的视图。

从这里开始,该往哪里走?

你已经学习了很多关于XcodeSwiftSwiftUI的知识,只是为了创建你的应用程序的分页界面。带着你的用户看到的清单,你将在接下来的两章中创建HIITFit原型的视图。