使用SwiftUI的声明性语法,创建、修改和组合视图,以便使用Scrumdinger的应用程序来管理会议。通过将一组视图排列在一起,创建会议计时器屏幕。随着您在模块中的进展,您将会反复回顾计时器屏幕,以便朝着最终设计的目标进行工作。
按照以下步骤开始您的新项目,或者打开已完成的项目,自行探索其中的代码。
第1节
创建项目
在整个模块中,通过创建Scrumdinger应用程序,您将学习应用程序开发的基础知识。在向应用程序添加新功能的过程中,您将探索Xcode和SwiftUI的基础知识。在本节中,您将创建Scrumdinger的Xcode项目。
步骤1
使用iOS App模板创建一个新项目。
步骤2
在项目选项中,将产品命名为“Scrumdinger”,点击界面弹出菜单,并选择SwiftUI。
模板包含了一个根视图的起始文件ContentView.swift,以及定义应用程序入口点的文件ScrumdingerApp.swift。
提示:
如果您对Xcode还不熟悉,请了解主窗口的相关信息,并了解如何创建一个项目。
步骤3
选择一个保存项目的位置。
第2节
组合视图
视图定义了您的用户界面的一部分。它们是应用程序的构建块。通过将小而简单的视图组合在一起,您可以构建一个复杂的视图。在本节中,您将构建计时器屏幕的标题,以显示会议的已用时间和剩余时间。
步骤1
打开ContentView.swift。
默认的SwiftUI视图文件声明了两个结构体。第一个结构体遵循View协议,该协议有一个要求:一个返回View的body属性。在body属性中,您描述视图的内容、布局和行为。第二个结构体为该视图定义了一个预览,以在画布上显示。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
您将对ContentView.swift进行重构,以为其指定一个与您的应用程序目的相关的名称。
步骤2
对ContentView结构体进行控制点击,选择Refactor > Rename,并将结构体重命名为MeetingView。
您还可以将预览结构体重命名为MeetingView_Previews,以保持命名的一致性。
步骤3
将现有body的内容替换为ProgressView,并使用占位数据初始化视图。
当您在项目导航器中选择一个SwiftUI文件时,画布会在编辑器旁边打开。画布会显示运行时视图的预览。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
ProgressView(value: 10, total: 15)
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView()
}
}
步骤4
将进度视图的值从10更改为5,并观察画布中的进度视图更新。
您将使用进度视图来显示Scrum期间已经过的时间的百分比。进度视图还可以显示不确定的进度,比如当应用程序正在加载数据时。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
ProgressView(value: 5, total: 15)
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView()
}
}
步骤5
按住Command键点击ProgressView,然后选择“Embed in VStack”。
堆栈将视图水平、垂直或前后分组。您可以使用堆栈来组合和层叠视图组件。
步骤6
在代码编辑器中创建一个HStack,点击库按钮,并将一个文本视图拖到HStack中,并设置值为"Seconds Elapsed"。
无论您使用源代码编辑器、画布、库或检查器来修改视图,您的代码都会保持更新。
步骤7
添加另一个值为"Seconds Remaining"的文本视图。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
VStack {
ProgressView(value: 5, total: 15)
HStack {
Text("Seconds Elapsed")
Text("Seconds Remaining")
}
}
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView()
}
}
步骤8
将每个文本视图嵌套在一个VStack中。
步骤9
在第一个文本视图下方添加一个标题为"300"、系统图片为"hourglass.tophalf.fill"的标签。
该图像使用了SF Symbols 4中的一个。系统将这些符号视为字体,因此它们会根据用户设备的设置进行动态缩放。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
VStack {
ProgressView(value: 5, total: 15)
HStack {
VStack {
Text("Seconds Elapsed")
Label("300", systemImage: "hourglass.tophalf.fill")
}
VStack {
Text("Seconds Remaining")
}
}
}
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView()
}
}
步骤10
在第二个文本视图下方添加一个标题为"600"、系统图片为"hourglass.bottomhalf.fill"的标签。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
VStack {
ProgressView(value: 5, total: 15)
HStack {
VStack {
Text("Seconds Elapsed")
Label("300", systemImage: "hourglass.tophalf.fill")
}
VStack {
Text("Seconds Remaining")
Label("600", systemImage: "hourglass.bottomhalf.fill")
}
}
}
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView()
}
}
第3节
修改和样式化视图
现在您已经在标题中创建了基本视图,您将对会议计时器屏幕的其余部分进行原型设计和样式设置。您将添加内置修饰符来调整标题的外观。您还将创建额外的堆栈和视图,并开始添加控件。
您将通过调整视图的间距来开始样式化标题。
步骤1
在每个VStack之间添加一个spacer,以利用包含父视图中的可用空间。
步骤2
在包围“Seconds Elapsed”的VStack中添加前导对齐,并在包围“Seconds Remaining”的VStack中添加尾部对齐。
这些对齐方式覆盖了默认的居中对齐方式。某些系统使用左对齐和右对齐。SwiftUI使用前导对齐和尾部对齐来简化您的应用程序的本地化。
提示
您还可以通过选择VStack并在属性检查器中使用对齐选项来设置对齐方式。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
VStack {
ProgressView(value: 5, total: 15)
HStack {
VStack(alignment: .leading) {
Text("Seconds Elapsed")
Label("300", systemImage: "hourglass.tophalf.fill")
}
Spacer()
VStack(alignment: .trailing) {
Text("Seconds Remaining")
Label("600", systemImage: "hourglass.bottomhalf.fill")
}
}
}
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView()
}
}
步骤3
对文本视图添加.font(.caption)修饰符以减小文本的大小。
要自定义SwiftUI视图,您可以调用称为修饰符的方法。每个修饰符都返回一个新的视图。您可以在单个视图上使用多个修饰符。要链式调用修饰符,请将它们垂直堆叠。
现在标题具有适当的间距,您将为屏幕中央显示的圆形计时器视图创建一个占位符。
步骤4
添加一个具有边框的圆形形状作为占位符。
您将在以后的教程中完善圆形计时器视图的设计。
import SwiftUI
struct MeetingView: View {
var body: some View {
VStack {
ProgressView(value: 5, total: 15)
HStack {
VStack(alignment: .leading) {
Text("Seconds Elapsed")
.font(.caption)
Label("300", systemImage: "hourglass.tophalf.fill")
}
Spacer()
VStack(alignment: .trailing) {
Text("Seconds Remaining")
.font(.caption)
Label("600", systemImage: "hourglass.bottomhalf.fill")
}
}
Circle()
.strokeBorder(lineWidth: 24)
HStack {
Text("Speaker 1 of 3")
}
}
}
}
通过创建页脚来完成会议计时器屏幕的原型设计。
步骤5
添加一个包含文本视图的HStack,显示"Speaker 1 of 3"。
步骤6
添加一个使用forward.fill图像作为标签的按钮。
暂时保留按钮的操作为空。在以后的教程中,您将使操作将计时器环推进到下一个发言人。
步骤7
在文本和按钮之间添加一个spacer。
步骤8
对顶层的VStack添加padding,将视图从边缘向内移动。
当您省略padding(_:)的参数时,SwiftUI会选择适合平台和展示上下文的默认值。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
VStack {
ProgressView(value: 5, total: 15)
HStack {
VStack(alignment: .leading) {
Text("Seconds Elapsed")
.font(.caption)
Label("300", systemImage: "hourglass.tophalf.fill")
}
Spacer()
VStack(alignment: .trailing) {
Text("Seconds Remaining")
.font(.caption)
Label("600", systemImage: "hourglass.bottomhalf.fill")
}
}
Circle()
.strokeBorder(lineWidth: 24)
HStack {
Text("Speaker 1 of 3")
Spacer()
Button(action: {}) {
Image(systemName: "forward.fill")
}
}
}
.padding()
}
}
第4节
补充辅助功能数据
SwiftUI具有内置的辅助功能,因此您可以在很少的额外工作下获得辅助功能支持。例如,文本视图中的字符串内容会自动对设备功能(如VoiceOver)进行辅助访问。但有时,您可能希望补充推断的数据,以增强用户的辅助功能体验。
步骤1
忽略标题栏中HStack的子视图的推断辅助功能标签和值。
在接下来的几个步骤中添加补充数据可以改进辅助功能体验。
步骤2
为HStack添加辅助功能标签,传递一个有意义的标签名称。
考虑标签和值中是否有足够的上下文让用户理解元素的目的。在这种情况下,您可以通过添加一个标签来补充数据,让VoiceOver用户只需听取一个输出的标签,显示最重要的信息。
步骤3
为剩余时间添加辅助功能值到HStack。
因为您有意忽略了子视图的值,所以您需要为HStack添加一个值。否则,SwiftUI会自动推断子视图的值。
步骤4
为前进按钮添加辅助功能标签。
默认情况下,VoiceOver会读取图像的系统名称:forward.fill。当您添加辅助功能标签时,VoiceOver会先读取标签文本,然后是内在的辅助功能特征:“下一个发言者。按钮。”
使用这四个修饰符,您可以增强用户的辅助功能体验。
MeetingView.swift
import SwiftUI
struct MeetingView: View {
var body: some View {
VStack {
ProgressView(value: 5, total: 15)
HStack {
VStack(alignment: .leading) {
Text("Seconds Elapsed")
.font(.caption)
Label("300", systemImage: "hourglass.tophalf.fill")
}
Spacer()
VStack(alignment: .trailing) {
Text("Seconds Remaining")
.font(.caption)
Label("600", systemImage: "hourglass.bottomhalf.fill")
}
}
.accessibilityElement(children: .ignore)
.accessibilityLabel("Time remaining")
.accessibilityValue("10 minutes")
Circle()
.strokeBorder(lineWidth: 24)
HStack {
Text("Speaker 1 of 3")
Spacer()
Button(action: {}) {
Image(systemName: "forward.fill")
}
.accessibilityLabel("Next speaker")
}
}
.padding()
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView()
}
}