List(expandWeather, children: \.weathers) { weather in
Label(weather.name, systemImage: weather.icon)
}
最后得到的就是一个可以展开的列表,当然我们可以构造更加复杂的多级展开列表,其原理是一样的,都是在子数据中嵌套更多数据类型相同的子数据。 样式
List 有多种样式,系统为我们提供了多种 ListStyle。其中,iOS 比较常用的除了系统默认样式外,还有 GroupedListStyle 和 InsetGroupedListStyle。 ForEach 基本使用 ForEach 能通过循环从集合数据中快速构建视图。集合数据 data 可以是 Range<Int> 类型,也可以是元素遵循 Identifiable 协议的数组。
比如:
ForEach(0..<2) { idx in
Text("\(idx)")
}
或者,我们仍然以上文的 weathers 作为 data ,
ForEach(weathers) { weather in
Text(weather.name)
}
ForEach 里有个参数 id,它用来保证数据的唯一性。上例中我们并没有显示地调用它,因为对 Range 类型的 data 而言,其 id 默认值就是 Int 元素的值,而 weathers 中的 Weather 实例,我们已经给 id 默认赋值为 UUID() 了,ForEach 会通过 keyPath 取到其中的 id,所以我们也不必显示传参。
如果我们只是想通过一个普通的字符串数组去实现循环创建视图,那么 id 可以显示指定为 \.self,即使用字符串本身作为 id 来保证数据的唯一性。
ForEach(["A", "B"], id: \.self) { str in
Text(str)
}
编辑操作
还记得我们前面提到过得 EditButton 吗?之前我们并没有具体讲解它的用法,现在我们可以见到它的具体使用了。
ForEach 和 List 配合使用,可以轻松地对列表进行编辑操作:delete、move。还是以 weathers 作为数据源,我们构建列表视图:
var body: some View {
List {
ForEach(weathers) { v in
Label(v.name, systemImage: v.icon)
}
.onDelete(perform: onDelete)
.onMove(perform: onMove)
}
.navigationBarItems(trailing: EditButton())
}
func onDelete(offsets: IndexSet) {
weathers.remove(atOffsets: offsets)
}
func onMove(fromOffsets: IndexSet, toOffset: Int) {
weathers.move(fromOffsets: fromOffsets, toOffset: toOffset)
}
EditButton 终于登场了,试试对列表进行编辑操作。
这里的编辑操作只是单选操作,如果我们要多选呢?可以在 List 中绑定 selection 数据,通过它对多条数据同时操作。这里就不举例了,读者可以按照这个思路去实现。 ScrollView
ScrollView 只有一个构建方法: