SwiftUI简介:使用TableView创建简单的应用程序

在WWDC 2019期间,最大最激动人心的时刻之一就是SwiftUI的发布公告。 SwiftUI是一个全新的框架,可让您以声明性方式编写更少的代码来设计和开发用户界面。

与通常与故事板一起使用的UIKit不同,SwiftUI完全基于软件。 但是,语法非常易于理解,并且可以使用“自动预览”快速查看项目。

由于SwiftUI使用Swift语言,因此您可以使用更少的代码来创建相同复杂度的应用程序。 此外,使用SwiftUI会自动允许应用程序使用诸如Dynamic TypeDark ModeLocalizationAccessibility的功能 。 此外,它在所有平台上都可用,包括macOSiOSiPadOSwatchOStvOS 。 因此,现在您的用户界面代码可以在所有平台上同步,从而使您有更多时间专注于特定于辅助平台的代码。

关于本文


开发人员必须及早学习如何使用SwiftUI,这一点很重要,因为Apple最终将把大部分注意力集中在此框架上。 在本文中,我们将介绍SwiftUI的基础知识,并学习如何通过创建一个简单的联系人列表来显示最小的导航,显示图像,文本和列表,以显示我们团队的所有成员。 选择团队成员时,应用程序将显示详细信息,其中包含用户的图像及其简短的传记。 让我们开始吧!

启动Xcode 11 。 在撰写本文时,Xcode 11仍处于beta版,因此某些功能可能无法按预期工作。 在本文中,我们将使用Swift 5 。 尽管本文不需要Swift的高级知识,但仍然建议您了解该语言的基础知识。

编者注:要在Xcode中预览Canvas中的图像并与之交互,请确保已安装Mac OS 10.15 beta。

使用SwiftUI创建一个新项目


让我们重新开始,以便您可以立即查看如何启动SwiftUI应用程序。 首先打开Xcode,然后选择“创建新的Xcode项目”。 对于iOS平台,选择Single View App。 输入应用程序的名称,然后填写文本字段。 但是,请确保在底部选中了“使用SwiftUI”。 如果您未选择此选项,则Xcode将为您创建一个故事板文件。

图片

Xcode会自动为您创建一个名为ContentView.swift的文件,令人惊讶的是,代码预览显示在右侧,如下所示。

图片

如果看不到预览,则必须单击预览区域中的“继续”按钮。 该项目的编译将花费一些时间。 请耐心等待编译完成。

现在,让我们看看如何修改这些文件以创建应用程序。

创建列表视图


创建列表视图的过程分为三个阶段。 第一个是在列表中创建行。 也许设计类似于UITableView。 为此,创建一个ContactRow。 第二阶段是将必要的数据传输到列表。 我有已经编码的数据,只需更改几下即可将列表与数据相关联。 最后一步只是添加导航栏并将列表嵌入到“导航视图”中。 这很简单。 现在让我们看看如何在SwiftUI中实现所有这些功能。

创建教师列表


首先,您需要创建一个视图以显示所有团队成员的列表,包括其个人资料和描述的照片。 让我们看看如何做到这一点。

如我们所见,生成的代码包含一个Text组件,其值为“ Hello World”。 在代码编辑器中,将代码值更改为“ Simon Ng”。

struct ContentView: View { var body: some View { Text("Simon Ng") } } 


如果一切正常,则应该在右侧看到自动更新。 正如我们所期望的,这是即时查看的效果。

图片

让我们在应用程序中添加一个新的Text元素。 这将是参与者的简短描述。 要在应用程序中添加新的界面元素,您需要单击右上角的+按钮。 随即出现一个新窗口,其中列出了不同的视图。 移动名称为Text的视图,并将其放在原始Text元素下,如下所示。

图片

注意左侧的代码:

 struct ContentView: View { var body: some View { VStack { Text("Simon Ng") Text("Placeholder") } } } 


您可能会注意到,在“文本视图”下添加了一个新的Text元素,其值为Simon Ng。 不同之处在于,现在该视图似乎已将视图包装在称为VStack的东西中。 VStack用于垂直堆栈,它是SwiftUI中自动布局的替代品。 如果您有为watchOS开发软件的经验,那么您可能会知道没有任何限制,而且所有元素都按组放置。 使用垂直堆栈时,所有视图将垂直排列。

现在,将“占位符”的文本更改为“ AppCoda的创始人”

接下来,让我们在该文本的左侧添加一个图像。 由于我们想将视图与现有视图水平放置,因此需要将VStack封装在HStack中。 为此,请执行⌘+单击VStack,然后选择Embed in HStack。 在下面看看这个:

图片

此代码应如下所示:

 struct ContentView: View { var body: some View { HStack { VStack { Text("Simon Ng") Text("Founder of AppCoda") } } } } 


尚无重大更改,但是现在我们将添加图像。 更改代码如下所示:

 struct ContentView: View { var body: some View { HStack { Image(systemName: "photo") VStack { Text("Simon Ng") Text("Founder of AppCoda") } } } } 


从iOS 13开始,Apple引入了一项称为SFSymbols的新功能。 苹果公司开发的SF Symbols是一个1500多个字符的集合,可以在应用程序中使用。 由于它们可以轻松地与San Francisco系统字体集成,因此字符可以自动与任何大小的文本进行垂直对齐。 由于我们还没有教师图片,因此我们将使用所谓的占位符。

图片

现在,让我们集中讨论一些较小的设计问题。 由于需要模拟UITableRow的外观, 因此我们将文本向左对齐(即,使其成为主要文本)。 为此,请执行⌘+单击 VStack并单击检查 。 选择左对齐图标,如下所示:

图片

接下来,我们将看到代码中的更改。 另外,代码将实时更改以显示新的更改。

 VStack(alignment: .leading) { ... } 


现在第二个文本视图是标题,让我们更改字体。 与以前一样,⌘+在预览模式下单击“ AppCoda的创始人”的文本表示形式,然后选择“检查”。 将字体更改为“副标题”,并实时显示预览和代码更改。

图片

我们还要更改颜色并将其设置为“灰色”。 此代码应如下所示:

 struct ContentView: View { var body: some View { HStack { Image(systemName: "photo") VStack(alignment: .leading) { Text("Simon Ng") Text("Founder of AppCoda") .font(.subheadline) .color(.gray) } } } } 


现在,在完成了一些样本的设计之后,我们进入了魔术部分。 看看创建列表有多容易。 执行⌘+单击HStack,然后单击“嵌入列表”。 瞧! 查看代码将如何自动更改,空白区域将显示5条漂亮的新行,每行均显示Simon Ng为团队成员。

图片

另外,请务必注意列表是如何在代码中创建的。 通过删除HStack并将其替换为重复的List,创建了一个表视图。 现在考虑节省了多少时间,减少了多少代码,避免了所有这些UITableViewDataSource,UITableViewDelegate,自动布局,暗模式的实现等。所有这些本身就说明了SwiftUI的强大功能。 但是,我们还远远不够。 让我们将一些实际数据添加到新列表中。

将数据连接到列表


我们需要的数据是团队成员及其传记的列表,以及包含所有图像的文件夹。 您可以在此处下载必要的文件。 您应该找到2个文件,名称分别为Tutor.swif t和Tutor.xcasset s。

下载后,将带有Swift扩展名的文件和资源文件夹导入Xcode项目。 要导入它们,只需将它们拖到项目导航器中即可。

Tutor.swif文件中, 我们声明Tutor结构并使之符合Identifiable协议。 您稍后将理解为什么这很重要。 我们还定义了变量id,名称,标题,bio和imageName。 最后,添加一些将在我们的应用程序中使用的测试数据。 Tutor.xcassets具有所有团队成员的图像。

返回ContentView.swift并按如下所示更改代码:

 struct ContentView: View { //1 var tutors: [Tutor] = [] var body: some View { List(0..<5) { item in Image(systemName: "photo") VStack(alignment: .leading) { Text("Simon Ng") Text("Founder of AppCoda") .font(.subheadline) .color(.gray) } } } } #if DEBUG struct ContentView_Previews : PreviewProvider { static var previews: some View { //2 ContentView(tutors: testData) } } #endif 


一切都非常简单:
  1. 定义一个称为tutors的新变量,该变量是Tutor结构的空数组。
  2. 由于我们为ContentView结构定义了一个新变量,因此,您还必须修改ContentView_Previews以显示此更改。 将tutors参数设置为testData。

预览中不会有任何更改,因为我们尚未使用测试数据。 要显示测试数据,请更改代码,如下所示:

 struct ContentView: View { var tutors: [Tutor] = [] var body: some View { List(tutors) { tutor in Image(tutor.imageName) VStack(alignment: .leading) { Text(tutor.name) Text(tutor.headline) .font(.subheadline) .color(.gray) } } } } 


确保ContentView使用辅导员在屏幕上显示数据。

你去! 查看视图如何改变。

图片

图像显示为正方形。 我希望他们看起来更圆滑。 让我们看看如何制作带有圆角的图像。 在右上角,单击+按钮,然后转到第二个选项卡。 这将显示可添加到图像的布局修改器列表。

图片

查找“转角半径”,将其从预览窗口拖动到图像上。 您应该看到更改的代码,并且预览图像将更改为以下内容。

图片

但是,弯曲半径3太小。 因此,将其更改为40。这样,我们得到了漂亮的圆形图片。

图片

单元格和列表已准备就绪! 接下来,您需要在用户单击单元格时显示详细信息。 让我们开始创建导航。

创建导航


导航视图将现有视图包装在导航栏和导航控制器中。 大概您已经熟悉了Storyboard,并且知道将视图嵌入导航界面非常简单。 您只需要单击几下。

在SwiftUI中,将List视图包装在NavigationView中也非常简单。 您所要做的就是更改代码,如下所示:

 ... var body : some View { NavigationView { List(tutors) { tutor in ... } } } ... 


您必须将列表代码包装在NavigationView中。 默认情况下,导航栏没有标题。 预览应将列表向下移动,中间留出很大的空白。 这是因为我们没有为导航栏设置标题。 要解决此问题,您需要通过添加以下代码行(即.navigationBarTitle)来设置标头:

 ... var body : some View { NavigationView { List(tutors) { tutor in ... } .navigationBarTitle(Text("Tutors")) } } ... 


现在屏幕应该看起来像这样:

图片

接下来,设置导航按钮。 NavigationButton会导致一个新屏幕,该屏幕位于导航堆栈中。 正如将列表包装在NavigationView中一样,我们需要使用NavigationButton包装列表的内容,如下所示:

 ... var body : some View { NavigationView { List(tutors) { tutor in NavigationButton(destination: Text(tutor.name)) { Image(tutor.imageName) VStack(alignment: .leading) { Text(tutor.name) Text(tutor.headline) .font(.subheadline) .color(.gray) } } } .navigationBarTitle(Text("Tutors")) } } ... 


团队成员名称现在显示在详细视图中。 现在是时候检查一下了。

在当前的预览模式下,您无法与视图进行交互。 通常,当您单击预览时,会发生简单的代码选择。 要运行测试并检查与用户界面的交互,必须单击右下角的播放按钮。

图片

视图将变暗,您可能需要等待几秒钟,直到整个模拟器加载完毕,才可以与视图进行真正的交互。

图片

下载完成后,您可以单击该单元格,它将转到堆栈上的新视图,其中将显示所选单元格的名称。

图片

在继续实现详细视图之前,让我向您展示一个技巧性的技术,该技术将使您的代码更易读。 ⌘+单击导航按钮,然后选择“提取子视图”。

oom! 您可以看到NavigationButton中的所有代码都是以全新的结构创建的,这使其非常清晰易读。 将ExtractedView重命名为TutorCell。

现在,您可以在TutorCell中得到错误。 这是因为我们没有将tutor参数传递给此结构。 纠正错误非常简单。 向TutorCell结构添加一个新常量,如下所示:

 struct TutorCell: View { let tutor: Tutor var body: some View { ... } } 


并且,在ContentView中,通过将行更改为添加缺少的参数:

 ... List(tutors) { tutor in TutorCell(tutor: tutor) }.navigationBarTitle(Text("Tutors")) ... 


仅此而已! 有一个列表和单元格,它们都经过深思熟虑,并按要求的顺序排列! 接下来,我们将创建一个详细视图,其中将显示有关该老师的所有信息。

图片

创建一个视图以显示详细信息。


让我们通过转到文件>新建>文件来创建一个新文件。 在iOS下,选择SwiftUI View并将其命名为TutorDetail

图片

在预览中,已经创建了主基本视图。 让我们和他一起工作。 首先,单击+按钮,然后将图像放置在已内置的Text视图上。 将图像名称设置为“ Simon Ng”。 西蒙的照片应该出现。 现在更改代码,如下所示:

 struct TutorDetail: View { var body: some View { //1 VStack { //2 Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) //3 Text("Simon Ng") .font(.title) } } } 


通常,此代码足够清晰,但是如果需要澄清,请不要担心。 这是发生了什么:
  1. 首先,我们将所有视图打包到垂直堆栈中。 这对于我们将采用的设计布局至关重要。
  2. 然后我们拍摄西蒙的图像并对其进行动画处理。 首先,将图像片段设置为圆形。 由于可以将圆适应不同的图像尺寸,因此它比设置cornerRadius更为有效。 我们添加带有白色框架的圆形叠加层,以提供漂亮的橙色框架。 最后,我们将添加一些阴影以提供一定的图像深度。
  3. 我们的最后一行代码将教师的姓名字体设置为标题字体。


图片

您还需要添加两个文本视图:标题和简历。 将两个文本视图拖到带有教师名称的文本视图下方,然后进行编辑:

 struct TutorDetail: View { var body: some View { VStack { Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) Text("Simon Ng") .font(.title) Text("Founder of AppCoda") Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") } } } 


图片

好消息是我们有文本视图。 坏消息是它们看起来很糟,没有显示标题和详细说明之间的区别。 此外,传记的文本视图不会显示所有文本。 让我们修复它。

如下更新代码:

 struct TutorDetail: View { var body: some View { VStack { Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) Text("Simon Ng") .font(.title) //1 Text("Founder of AppCoda") .font(.subheadline) //2 Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") .font(.headline) .multilineTextAlignment(.center) } } } 


  1. 首先,我们使用副标题字体安装“ AppCoda的创始人”。
  2. 同样,我们使用标题字体设置传记的文本表示形式。 我们还将使文本与.multilineTextAlignment(.center)对齐


图片

让我们修复以下错误。 我们需要显示传记文本表示形式的整个文本。 可以通过添加新的代码行轻松地完成此操作:

 ... Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") .font(.headline) .multilineTextAlignment(.center) .lineLimit(50) ... 


图片

一切看起来都很好。 我要进行的最后一项设计更改是。 传记的标题和文字表示过于接近。 我想在这两个视图之间留一些空间。 另外,我想在所有扭曲处添加一些压痕,以使它们不会碰到设备的边缘。 确保按以下方式更改代码:

 struct TutorDetail: View { var body: some View { VStack { Image("Simon Ng") .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) Text("Simon Ng") .font(.title) Text("Founder of AppCoda") .font(.subheadline) //1 Divider() Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") .font(.headline) .multilineTextAlignment(.center) .lineLimit(50) //2 }.padding() } } 


在这里,我们进行一些更改:
  1. 添加分隔符就像调用Divider()一样容易
  2. 要将填充添加到整个垂直堆栈,必须在VStack声明的末尾调用.padding()


图片

仅此而已! 恭喜你! 详细视图屏幕已准备就绪。 仍然仅是连接我们的教师列表及其详细说明。 这很简单。

资料传输


要传输数据,您需要在TutorDetail结构中声明一些参数。 在声明主体变量之前,添加以下变量:

 var name: String var headline: String var bio: String var body: some View { ... } 


这些是我们将从ContentView传递的参数。 进行以下更改:

 ... var body: some View { VStack { // 1 Image(name) .clipShape(Circle()) .overlay( Circle().stroke(Color.orange, lineWidth: 4) ) .shadow(radius: 10) //2 Text(name) .font(.title) //3 Text(headline) .font(.subheadline) Divider() //4 Text(bio) .font(.headline) .multilineTextAlignment(.center) .lineLimit(50) //5 }.padding().navigationBarTitle(Text(name), displayMode: .inline) } ... 


  1. 用变量名称替换图像的教师名称
  2. 用标题变量替换标题文本
  3. 最后,用变量bio替换文本的长段
  4. 还添加了一行代码,用于将导航栏的标题设置为教师的姓名。


最后但并非最不重要的一点是,我们需要将缺少的参数添加到TutorDetail_Previews结构中。

 #if DEBUG struct TutorDetail_Previews : PreviewProvider { static var previews: some View { TutorDetail(name: "Simon Ng", headline: "Founder of AppCoda", bio: "Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.") } } #endif 


在上面的代码中,我们添加了缺少的参数,并使用以前的参数填写信息。

您可能想知道#if DEBUG /#endif指令发生了什么。 这意味着这些命令中包含的所有代码仅在出于调试目的而预览时才会执行。 在您的上一个应用程序中将不会。

由于信息也保持不变,因此没有任何更改。

图片

因此,最后一步是将该视图与列表相关联。 切换到ContentView.swift文件。 您需要做的就是在TutorCell结构中更改一行代码。 将NavigationButton代码更改为以下代码:

 ... var body: some View { return NavigationButton(destination: TutorDetail(name: tutor.name, headline: tutor.headline, bio: tutor.bio)) { ... } } ... 


填写相关数据时,您需要将目的地更改为TutorDetail,而不是显示带有教师姓名的视图。 此代码应如下所示:

图片

单击播放按钮,然后与视图进行交互。 如果一切正常,该应用程序也将正常运行。

只需选择成员条目之一:

图片

然后,参与者的详细信息将显示在详细屏幕上。

图片

结论


本文介绍SwiftUI的基础知识。 现在,可以方便地创建简单的应用程序,例如任务计划程序等。 我建议看一下下面的一些资源,例如Apple文档和有关此框架的WWDC 2019会议。

SwiftUI文档
SwiftUI教程
SwiftUI简介:构建您的第一个应用程序
SwiftUI基础

这个框架是Apple的未来,因此从它开始就很棒。 请记住,如果不确定代码,请尝试使用自动预览,并查看是否可以直接更改用户界面以查看代码的生成方式。 如果您有任何疑问,请随时在下面的评论中提问。

作为参考,您可以在此处下载完成的项目。

Source: https://habr.com/ru/post/zh-CN461645/


All Articles