一同养成写作习气!这是我参加「日新计划 4 月更文应战」的第12天,点击查看活动概况。

前言:写这篇文章已经快挨近12点了,写了快2个小时,总的来说,要想讲清楚一个知识点还是没那么简略,首要语言不能太杂乱,不能有太多专有名词,假如有些转有名词避不开,也要想方法举个比如。果然,蜕变的路上总是困难和孤单的。

今日职言:不要企图说服读者,不要以讲道理的方法推进论题。

在本章中,你将学会怎么运用循环遍历的方法创立一个列表,并可自界说参数动态生成列表。

假如你接触过UIKit的话,应该会用过tableView组件创立列表,咱们日子顶用的许多App根本都是列表的方法。

例如的信息列表、手机体系设置、音乐列表等等……

SwiftUI极简教程12:List列表和ForEach循环的使用

根本上大多数App,特别是资讯类App都少不了列表的存在。

而在SwiftUI中,咱们用List替代了原有tableView,使得代码愈加简练易懂。

由于List组件在不同场景下的运用不同,本章节分成4个部分解说。

1、简略文字列表;

2、图片+文字列表;

3、列表数据整合;

4、Identifiable协议的运用;

榜首部分:简略文字列表

首要,咱们先创立一个新项目,命名为SwiftUIList。

SwiftUI极简教程12:List列表和ForEach循环的使用

咱们在ContentView.swift文件中,创立一个简略的列表。

List的结构方法和之前学习的VStack很类似,将内容包裹在里边形成列表。

struct ContentView: View {
var body: some View {
   //简略的列表
List {
Text(“第1页")
Text(“第2页")
Text(“第3页")
Text(“第4页")
}
}
}

SwiftUI极简教程12:List列表和ForEach循环的使用

咱们看到List里边都是Text文本,并且仅仅内容不同。

这时候,咱们能够运用ForEach的方法把代码抽离出来,也就不需要写那么多相似的代码。

struct ContentView: View {
var body: some View {
// 简略的列表
List {
ForEach(1 ... 4, id: \.self) { index in
Text("第 \(index)页")
}
}
}
}

SwiftUI极简教程12:List列表和ForEach循环的使用

在运用ForEach遍历创立视图时,需要用id来标识内容,当里边的内容发现变化时,ForEach就能够主动更新UI。

简略来读一下代码内容:

咱们传递给ForEach一个规模的值,用来循环遍历生成列表。

而它的id(标识符)被设置为值本身self,也便是前面设置的1、2、3、4。

然后用index参数存储循环的值。

咱们在这里遍历了4次,每一次展示一个Text,Text里边的文字是“第”+{index}+“页”,index的参数值从1~4;

这样,咱们就得到了一个列表。

当然,还有更简略的遍历方法。

struct ContentView: View {
var body: some View {
// 简略的列表
List {
ForEach(1 ... 4, id: \.self) {
Text("第 \($0)页")
}
}
}
}

SwiftUI极简教程12:List列表和ForEach循环的使用

在这里,咱们省掉索引参数index,而运用简化的$0,它引证闭包的榜首个参数,直接将数据集合传递给List。

这样,也能够达到列表的作用,并且使得代码愈加简略。

第二部分:图片+文字列表

好,下面进阶一下,咱们测验完成下面的UI设计稿。

SwiftUI极简教程12:List列表和ForEach循环的使用

首要剖析下它的结构。

一个列表里,有Image、Text,他们是横向HStack排布。

咱们先在Assets.xcassets导入咱们所需的图片。

SwiftUI极简教程12:List列表和ForEach循环的使用

SwiftUI极简教程12:List列表和ForEach循环的使用

并且咱们已经提早给图片命好名了,方便咱们接下来运用它们。

咱们回到ContentView.swift文件中,创立2个数组,寄存咱们的图片和文字。

//界说数组,寄存数据
var myImages = ["weixin","weibo","qq","phone","mail"]
var myNames = ["这是微信","这是微博","这是QQ","这是电话","这是邮箱"]

SwiftUI极简教程12:List列表和ForEach循环的使用

咱们看到报错了,但又没有彻底报错。

这是由于咱们界说了一个动态数组,但在代码中没有用到,所以体系告知咱们界说的数组称号没有被运用罢了。

没事的,咱们继续。

咱们在body里边创立咱们需要的代码。

struct ContentView: View {
 //界说数组,寄存数据
 var myImages = ["weixin","weibo","qq","phone","mail"]
 var myNames = ["这是微信","这是微博","这是QQ","这是电话","这是邮箱"]
 var body: some View {
// 列表
List(myImages.indices, id: \.self) { index in
HStack {
Image(self.myImages[index])
.resizable()
.frame(width: 40, height: 40)
.cornerRadius(5)
Text(self.myNames[index])
}
}
}
}

SwiftUI极简教程12:List列表和ForEach循环的使用

咱们还是构建了一个列表,不过运用myImages作为目录,也便是myImages.indices。

然后图片遍历用myImages数组,文字遍历用myNames数组。

是不是很简略,比起以前用UIKit的时候,要给cell协议和声明,SwiftUI几行代码就搞定了。

第三部分:列表数据整合

下面,咱们再进阶一下。

上面的代码中,咱们发现假如是图片+文字,那么咱们创立了2个数组,假如是愈加杂乱的场景,咱们岂不是要树立一堆的数组数据?

不不不,这必定不够高雅。

最好的方法应该是,无论咱们多少数组数据,咱们都用一个数组包裹住。

咱们回到UI稿中。

SwiftUI极简教程12:List列表和ForEach循环的使用
有没有方法,把Image和Text界说出来,然后Image和Text是一个数组?

有的!这时候,咱们需要创立一个结构体,叫做Message,并界说好里边的变量。

代码如下:

struct Message {
 var name: String
 var image: String
}

运用这个Message结构体,咱们将本来的myImages、myNames数组组合成一个数组。

咱们界说了一个数组Messages,它里边的内容是Message结构体。

代码如下:

// 界说数组,寄存数据
var Messages = [
Message(name: "这是微信", image: "weixin"),
Message(name: "这是微博", image: "weibo"),
Message(name: "这是QQ", image: "qq"),
Message(name: "这是电话", image: "phone"),
Message(name: "这是邮箱", image: "mail")
]

构建好了今后,咱们回到body里边,把里边的引证的参数值换成数组Messages,运用结构体Message遍历数据,List中运用image特点作为仅有的标识符。

一起,要把里边Image的参数引证结构体Message的image参数,Text引证结构体Message的name参数。

代码如下:

// 列表
List(Messages, id: \.image) { Message in
 HStack {
  Image(Message.image)
   .resizable()
   .frame(width: 40, height: 40)
   .cornerRadius(5)
  Text(Message.name)
 }
}

那么,终究的结果和咱们之前做的作用是相同的。

仅有不相同的是,咱们的代码看起来高雅多了。

SwiftUI极简教程12:List列表和ForEach循环的使用

小结一下:

咱们创立了一个结构体Message,它界说了2个变量,1个是image图片,是Strring类型,另一个是name称号,也是Strring类型。

然后咱们界说个一个数组Messages(注意加了S),这个数组里边是结构体Message,并赋予了结构体里边2个变量的值;

然后在在body主代码块List里边,用Messages数据作为引证值数据,然后用结构体Message遍历数据。

最终把里边的Image和Text中的值换成结构体中变量的值。

第四部分:Identifiable协议的运用

完成第三部分今后,咱们的代码List就完美了么?

并不!

由于这个:

List(Messages, id: \.image)

咱们运用了image为Messages数组的仅有标识符,也便是List是通过image的仅有性找到对应数组的数据。

这样,咱们会面临一个问题,假如我有2个图片是相同的,但是它的name不相同。

咱们测验把Messages数组的数据换成下面这样:

// 界说数组,寄存数据
var Messages = [
 Message(name: "这是微信", image: "weixin"),
 Message(name: "这是第二个微信号", image: "weixin")
]

SwiftUI极简教程12:List列表和ForEach循环的使用

咱们发现,假如咱们运用image作为id,也便是仅有标识符的话。

假如我的数组里有2个image,假如它们的值相同,那么SwiftUI会以为这两个是同一个东西。

也便是,我都是图片都是“微信”,但称号不相同,但计算机以为两个都是微信,并且值相同,这是由于image作为id是仅有的。

这时候,咱们该怎么办?

咱们希望的结果是,Messages数组里,每一个结构体的数据都是仅有的。

那么咱们就不能在body构建仅有的标识符,应该在传值之前就在Message结构体里构建仅有的id。

struct Message {
var id = UUID()
var image: String
var name: String
}

在代码中,咱们添加了id特点,并用仅有标识符初始化它。

UUID()函数用于生成一个全局惟一的随机标识符。

UUID由128位数字组成,因此从理论上讲,具有两个相同标识符的可能性简直为零。

然后,咱们把body代码中的id,引证Message结构体的id。

// 列表
List(Messages, id: \.id) { Message in
 HStack {
  Image(Message.image)
   .resizable()
   .frame(width: 40, height: 40)
   .cornerRadius(5)
 Text(Message.name)
 }
}

这样,咱们就完成了List数据源的仅有。

SwiftUI极简教程12:List列表和ForEach循环的使用

再科普一个知识点。

咱们还能够设置结构体Message遵循Identifiable协议。

这样,遵循Identifiable的结构体就能够主动跟踪它的id作为仅有标识符,咱们也就不需要在body中指定id了。

完好代码如下:

import SwiftUI
struct ContentView: View {
// 界说数组,寄存数据
var Messages = [Message(image: "weixin", name: "这是微信"),Message(image: "weixin", name: "我的第二个微信号")]
var body: some View {
// 列表
List(Messages) { Message in
HStack {
Image(Message.image)
.resizable()
.frame(width: 40, height: 40)
.cornerRadius(5)
Text(Message.name)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Message: Identifiable {
var id = UUID()
var image: String
var name: String
}

SwiftUI极简教程12:List列表和ForEach循环的使用

恭喜你!完成了List的学习!

假如本专栏对你有帮助,无妨点赞、谈论、关注~