欢迎光临散文网 会员登陆 & 注册

SwiftUI学习100天(Day79 - 项目 16,第一部分)

2023-03-24 12:00 作者:爱上树の蜗牛  | 我要投稿

原创链接:https://www.hackingwithswift.com/100/swiftui

以下内容仅供学习参考:

现在你已经跨过了使用 UIKit 的难关,我们可以回到使用纯 SwiftUI 的更快乐的地方——我想你现在会更加感激它!

在这个项目中,你将学习 Swift 和 SwiftUI 的非常棒的功能组合;它确实有助于提高你的技能并让你灵活地创建功能强大的应用程序。是的,即使在 79 天到我们的 100 天,仍有许多新东西需要学习——正如 Lily Tomlin 所说,“通往成功的道路总是在建设中”!

今天你要完成三个主题,你将在其中了解自定义环境对象、选项卡视图等。

热门前景:简介

在这个项目中,我们将构建 Hot Prospects,这是一款用于跟踪你在会议上遇到的人的应用程序。你可能以前见过类似的应用程序:它会显示一个存储你的与会者信息的二维码,然后其他人可以扫描该代码将你添加到他们的潜在线索列表中,以便以后跟进。

这听起来可能很简单,但在此过程中我们将介绍大量真正重要的新技术:创建选项卡栏和上下文菜单、使用环境共享自定义数据、发送自定义更改通知等等。生成的应用程序很棒,但你在此过程中学到的东西将特别有用!

与往常一样,在我们开始实施我们的项目之前,我们有很多技术要介绍,所以请首先使用 App 模板创建一个新的 iOS 项目,并将其命名为 HotProspects。

让我们开始吧!

使用@EnvironmentObject 从环境中读取自定义值

你已经了解了如何使用@State单个视图的本地状态,以及如何用@ObservedObject让我们将一个对象从一个视图传递到另一个视图以便我们可以共享它。好吧,@EnvironmentObject更进一步:我们可以将一个对象放入环境中,这样任何子视图都可以自动访问它。

想象一下,我们在一个应用程序中有多个视图,所有视图都排成一条链:视图 A 显示视图 B,视图 B 显示视图 C,C 显示 D,D 显示 E。视图 A 和 E 都想访问同一个对象,但是要从 A 到 E,你需要经过 B、C 和 D,而他们不关心那个对象。如果我们正在使用@ObservedObject我们需要将我们的对象从每个视图传递到下一个视图,直到它最终到达可以使用它的视图 E,这很烦人,因为 B、C 和 D 不关心它。视图@EnvironmentObject A 可以将对象放入环境中,视图 E 可以从环境中读取对象,而视图 B、C 和 D 不必知道发生了什么——这样更好。

在我向你展示一些代码之前,还有最后一件事:环境对象使用ObservableObject你已经了解的相同协议,并且 SwiftUI 将自动确保共享相同环境对象的所有视图在更改时得到更新。

好的,让我们看一些代码,展示如何使用环境对象在两个视图之间共享数据。首先,这是我们可以使用的一些基本数据:

如你所见,它使用@MainActorObservableObject, 和@Published就像我们之前学到的一样——你积累的所有知识都会继续得到回报。

接下来我们可以定义两个 SwiftUI 视图来使用我们的新类。这些将使用@EnvironmentObject属性包装器表示此数据的值来自环境而不是在本地创建:

@EnvironmentObject属性包装器将自动在环境中查找实例User,并将找到的任何内容放入user属性中。如果它在环境中找不到User,你的代码就会崩溃,所以请小心。

我们现在可以将这两个视图放在一个地方,并发送一个User实例供它们使用:

这就是让我们的代码正常工作所需的一切——你现在可以运行该应用程序并更改文本字段以查看其值出现在下面的文本视图中。当然,我们可以在单个视图中表示这一点,但这样你就可以准确地看到使用环境对象时通信的无缝程度。

现在,这是聪明的部分。ContentView尝试将body的属性重写为

你会发现它的工作原理是一样的。我们现在放置userContentView的环境中,但因为EditViewDisplayView都是ContentView的子级,它们会自动继承其环境。

提示:鉴于我们明确地与其他视图共享我们的实例User,我个人倾向于删除private访问控制,因为它不准确。

现在,你可能想知道 SwiftUI 如何在.environmentObject(user) @EnvironmentObject var user: User之间建立联系——它如何知道将该对象放入正确的属性中?

嗯,你已经看到字典如何让我们使用一种类型作为键,另一种类型作为值。该环境有效地让我们将数据类型本身用作键,并将类型的实例用作值。一开始这有点让人费解,但可以这样想象:键是像IntStringBool之类的东西,值是 5、“你好” 和 true 之类的东西,这意味着我们可以说“给我Int”和我们会回来5。

使用 TabView 和 tabItem() 创建选项卡

导航视图非常适合让我们创建层次化的视图堆栈,让用户深入了解数据,但它们不能很好地显示不相关的数据。为此,我们需要使用 SwiftUI 的TabView,它会在屏幕底部创建一个按钮条,点击每个按钮会显示不同的视图。

将选项卡放在一个TabView就像将它们一一列出一样简单,如下所示:

然而,在实践中,你总是希望自定义选项卡的显示方式——在上面的代码中,选项卡栏将是一个空白的灰色区域。尽管你可以点击该灰色区域的左右部分来激活这两个选项卡,但这是一种非常糟糕的用户体验。

相反,最好将修饰符附加tabItem()TabView. 这使你可以自定义视图在选项卡栏中的显示方式,提供图像和一些文本显示在它旁边,如下所示:

除了让用户通过点击选项卡项来切换视图外,SwiftUI 还允许我们使用状态以编程方式控制当前视图。这需要四个步骤:

  1. 创建一个@State属性来跟踪当前显示的选项卡。

  2. 每当我们想跳转到不同的选项卡时,将该属性修改为新值。

  3. 将它作为绑定传递到 TabView,因此它会被自动跟踪。

  4. 告诉 SwiftUI 应该为该属性的每个值显示哪个选项卡。

其中前三个很简单,所以让我们把它们移开。首先,我们需要一些状态来跟踪当前选项卡,因此将其作为属性添加到ContentView

其次,我们需要在某处修改它,这将要求 SwiftUI 切换选项卡。在我们的小演示中,我们可以将onTapGesture()修饰符附加到第一个选项卡,如下所示:

第三,我们需要绑定到的TabView选择$selectedTab。这是在我们创建 TabView时作为参数传递的,因此请将你的代码更新为:

现在是有趣的部分:当我们说selectedTab = "Two" SwiftUI 如何知道代表哪个选项卡时?你可能认为可以将选项卡视为一个数组,在这种情况下,第二个选项卡将位于索引 1 处,但这会导致各种问题:如果我们将该选项卡移动到选项卡视图中的不同位置会怎样?

在更深层次上,它还打破了 SwiftUI 的核心概念之一:我们应该能够自由地组合视图。如果选项卡 1 是数组中的第二项,则:

  1. Tab 0 是第一个选项卡。

  2. 选项卡 1 是第二个选项卡。

  3. 标签 0 有一个onTapGesture()显示标签 1 的标签。

  4. 因此,选项卡 0 非常了解其父项 TabView配置方式。

这是一个非常糟糕的想法,因此 SwiftUI 提供了一个更好的解决方案:我们可以为每个视图附加一个唯一标识符,并将其用于选定的选项卡。这些标识符称为标签,并使用tag()如下修饰符附加:

所以,我们的整体观点是这样的:

现在代码可以工作了:你可以通过按下选项卡项或在第一个选项卡中激活我们的点击手势来在选项卡之间切换。

当然,只使用“One”和“Two”并不理想——这些值是固定的,因此它解决了视图移动的问题,但它们不容易记住。幸运的是,你可以改用任何你喜欢的值:为每个视图提供一个唯一且反映其用途的字符串标记,然后将其用于你的@State属性。从长远来看,这更容易使用,并且推荐使用整数。

提示:想同时使用NavigationViewTabView是很常见的,但你要小心:TabView应该是父视图,里面的选项卡根据需要有一个NavigationView,而不能反过来。


SwiftUI学习100天(Day79 - 项目 16,第一部分)的评论 (共 条)

分享到微博请遵守国家法律