ForEach 是 SwiftUI 中用于动态生成一系列视图的控制结构。它非常灵活,可以用在各种容器(如 VStack, HStack, ZStack, List 等)中,帮助你通过一组数据动态地渲染一组视图。
1. 基本用法#
ForEach 的基本用法是通过一个集合(数组、范围等)来创建一组重复的视图。它会为集合中的每个元素生成一个对应的视图。
例子:#
struct ContentView: View {
let items = ["Apple", "Banana", "Cherry"]
var body: some View {
VStack {
ForEach(items, id: \.self) { item in
Text(item)
.padding()
}
}
}
}- 解释:
ForEach(items, id: \.self):items是一个数组,id: \.self表示数组中的每个元素(这里是String类型)作为每个视图的唯一标识符。item in:对于items数组中的每一个元素,item表示当前元素。Text(item):为每个item创建一个Text视图。
输出:#
- 会在垂直堆叠(
VStack)中显示三个Text视图,分别显示Apple、Banana和Cherry。
2. 使用范围生成视图#
ForEach 还可以用于生成一系列基于范围的数据。例如,生成一个从 0 到 9 的数字列表。
例子:#
struct ContentView: View {
var body: some View {
VStack {
ForEach(0..<10) { number in
Text("Number \(number)")
.padding()
}
}
}
}- 解释:
ForEach(0..<10):这里使用的是一个范围(0..<10),它表示从 0 到 9(不包括 10)。- 对于每一个数字,
Text("Number \(number)")会生成一个对应的文本视图。
3. 使用自定义数据模型#
如果你有自定义数据模型(比如结构体或类的数组),你可以通过 ForEach 结合数据模型的属性来生成视图。
例子:#
struct Item {
var name: String
var description: String
}
struct ContentView: View {
let items = [
Item(name: "Apple", description: "A sweet fruit"),
Item(name: "Banana", description: "A yellow fruit"),
Item(name: "Cherry", description: "A small red fruit")
]
var body: some View {
VStack {
ForEach(items, id: \.name) { item in
VStack(alignment: .leading) {
Text(item.name)
.font(.headline)
Text(item.description)
.font(.subheadline)
}
.padding()
}
}
}
}- 解释:
ForEach(items, id: \.name):这里使用了items数组中的Item类型,id: \.name表示Item的name属性将作为每个视图的唯一标识符。VStack内部的Text显示每个项目的名称和描述。
4. 使用动态数据源#
ForEach 可以与动态数据源结合使用,特别适用于从网络或数据库加载数据并动态展示。
例子:#
class DataModel: ObservableObject {
@Published var items = [
Item(name: "Apple", description: "A sweet fruit"),
Item(name: "Banana", description: "A yellow fruit")
]
}
struct ContentView: View {
@ObservedObject var dataModel = DataModel()
var body: some View {
VStack {
ForEach(dataModel.items, id: \.name) { item in
VStack(alignment: .leading) {
Text(item.name)
.font(.headline)
Text(item.description)
.font(.subheadline)
}
.padding()
}
}
}
}- 解释:
- 这里使用
@ObservedObject来观察DataModel中的数据,items会随着数据的更新而自动刷新视图。
- 这里使用
5. 可更新的数据#
如果需要更新数据(例如在 ForEach 中修改数据项),可以通过绑定来实现动态更新。
例子:#
struct ContentView: View {
@State private var items = ["Apple", "Banana", "Cherry"]
var body: some View {
VStack {
ForEach(items, id: \.self) { item in
Text(item)
.padding()
}
Button("Add Item") {
items.append("Orange")
}
}
}
}- 解释:
- 使用
@State修饰items,允许它在视图中发生变化。 - 按钮的点击会向
items数组中添加一个新的项,ForEach会自动刷新视图。
- 使用
6. 配合 List 使用#
ForEach 常常与 List 一起使用,特别是在展示动态数据时。List 本身是一个容器,它可以自动处理滚动和视图复用,而 ForEach 用来生成每个列表项。
例子:#
struct ContentView: View {
let items = ["Apple", "Banana", "Cherry"]
var body: some View {
List {
ForEach(items, id: \.self) { item in
Text(item)
}
}
}
}- 解释:
ForEach生成每一行的内容,而List处理滚动和复用的逻辑。
7. 删除操作与 ForEach#
你可以结合 ForEach 和删除操作来动态更新视图,通常与 List 配合使用。
例子:#
struct ContentView: View {
@State private var items = ["Apple", "Banana", "Cherry"]
var body: some View {
List {
ForEach(items, id: \.self) { item in
Text(item)
}
.onDelete { indexSet in
items.remove(atOffsets: indexSet)
}
}
}
}- 解释:
- 使用
.onDelete修饰符来添加删除功能,允许用户从列表中删除项。
- 使用
总结:#
ForEach用于动态生成重复视图,适用于任何容器视图中。- 它需要一个数据源(数组、范围等)来循环生成视图,并通过
id来唯一标识每个视图。 ForEach和List配合使用时,可以处理滚动和视图复用,适合展示动态列表。