文章目录
-
- 一、简介
- 二、基本用法
-
- [2.1 静态数据](#2.1 静态数据)
- [2.2 动态数据](#2.2 动态数据)
-
- [2.2.1 直接使用 List 初始化](#2.2.1 直接使用 List 初始化)
- [2.2.2 使用 List 和 ForEach](#2.2.2 使用 List 和 ForEach)
- 三、常用属性
-
- [3.1 显示/隐藏分割线](#3.1 显示/隐藏分割线)
- [3.2 设置背景行颜色](#3.2 设置背景行颜色)
- [3.3 列表样式](#3.3 列表样式)
- [3.4 删除](#3.4 删除)
- [3.5 排序](#3.5 排序)
- [3.6 下拉刷新](#3.6 下拉刷新)
- [3.7 设置标题](#3.7 设置标题)
- [3.8 多选或单选](#3.8 多选或单选)
-
- [3.8.1 多选](#3.8.1 多选)
- [3.8.2 单选](#3.8.2 单选)
- [3.8.3 注意事项](#3.8.3 注意事项)
- 四、综合案例
一、简介
在 SwiftUI
中,List
组件用于创建可滚动的列表界面。它类似于UIKit
中的 UITableView
,但使用起来更加简洁和直观。List
可以显示静态或动态的数据,并支持多种样式和交互。
二、基本用法
2.1 静态数据
List
可以包含一系列静态的视图元素,这些元素会按照添加的顺序依次显示在列表中。
swift
List {
Text("第一项")
Text("第二项")
Text("第三项")
}

在这个例子中,我们创建了一个简单的列表,其中包含三个Text
视图。每个 Text
视图代表列表中的一行。
2.2 动态数据
通常,我们会使用动态的数据集合来填充列表。List
可以与 Swift
的数组、集合等数据结构结合使用。
2.2.1 直接使用 List 初始化
以下是一个使用数组创建动态列表的示例:
swift
import SwiftUI
struct ContentView: View {
let items = ["苹果", "香蕉", "橙子", "葡萄"]
var body: some View {
List(items, id: \.self) { item in
Text(item)
}
}
}

在这个示例中,items
是一个字符串数组,id: \.self
表示使用数组元素本身作为唯一标识符。闭包{ item in Text(item) }
定义了列表中每一行的显示内容,这里是将数组中的每个元素以Text
视图的形式显示出来。
特点:
- 简洁性: 这种方式是直接将数据数组传递给
List
,然后使用闭包来定义每个列表项的视图。它更为简洁,适合简单的列表。 - 自动识别:
SwiftUI
会自动识别数据并为每个元素创建一个列表项。 - 适用场景: 适用于简单的、单一数据源的列表。
2.2.2 使用 List 和 ForEach
ForEach
用于在 List
中迭代显示动态数据。
swift
struct DynamicView: View {
let items = ["苹果", "香蕉", "橙子", "葡萄"]
var body: some View {
List{
ForEach(items,id:\.self){ item in
Text(item)
}
}
}
}
特点:
- 灵活性: 这种方式通过
ForEach
显式地遍历数据数组,并在 List 中构建每个列表项。这提供了更大的灵活性。 - 组合内容: 在
List
中使用ForEach
可以更方便地与其他视图组合,比如在同一个列表中添加静态视图、Section
、或者其他动态内容。 - 适用场景: 适用于复杂的列表视图,特别是当你需要在列表中混合使用不同类型的内容时。
三、常用属性
3.1 显示/隐藏分割线
默认情况下,List
会显示分隔线来区分每一行。如果你想隐藏分隔线,可以使用 listRowSeparator
修饰符。
swift
struct DynamicView: View {
let items = ["苹果", "香蕉", "橙子", "葡萄"]
var body: some View {
List(items, id: \.self) { item in
Text(item)
.listRowSeparator(.hidden)
}
}
}

3.2 设置背景行颜色
使用 listRowBackground
修饰符为列表中的每一行设置背景颜色。
swift
struct DynamicView: View {
let items = ["苹果", "香蕉", "橙子", "葡萄"]
var body: some View {
List(items, id: \.self) { item in
Text(item)
.listRowSeparator(.hidden)
.listRowBackground(Color.gray.opacity(0.2))
}
}
}

3.3 列表样式
List
支持多种不同的样式,你可以使用listStyle
修饰符来设置。常见的列表样式:
DefaultListStyle
: 使用系统默认的列表样式。这是List
的默认样式。PlainListStyle
: 提供一个简单的列表样式,没有分隔线和背景。GroupedListStyle
: 将列表项目分组,通常用于设置界面中的分节列InsetGroupedListStyle
: 类似于GroupedListStyle
,但项目分组时有内边距。这种样式在iOS
上看起来与设置应用中的列表样式类似。InsetListStyle
: 列表项有内边距,但不分组。SidebarListStyle
: 专为侧边栏设计的列表样式,通常在macOS
和iPadOS
的多列布局中使用。
以PlainListStyle
为例:
swift
struct DynamicView: View {
let items = ["苹果", "香蕉", "橙子", "葡萄"]
var body: some View {
List(items, id: \.self) { item in
Text(item)
}
.listStyle(PlainListStyle())
}
}

3.4 删除
onDelete
支持在列表中删除元素的功能。
swift
struct DynamicView: View {
@State var items = ["苹果", "香蕉", "橙子", "葡萄"]
var body: some View {
List{
ForEach(items,id:\.self){ item in
Text(item)
}
.onDelete(perform: deleteItems)
}
}
// 删除元素
func deleteItems(at offsets:IndexSet){
items.remove(atOffsets: offsets)
}
}

解释:
func deleteItems(at offsets: IndexSet)
at
: 这是外部参数名。在函数调用时,使用这个名称来指示参数的目的或位置。它帮助使函数调用更加可读和清晰。offsets
: 这是内部参数名。在函数实现中使用这个名称来引用传递给函数的IndexSet
值。
3.5 排序
onMove
支持在列表中移动元素的功能
swift
struct DynamicView: View {
@State var items = ["苹果", "香蕉", "橙子", "葡萄"]
var body: some View {
List{
ForEach(items,id:\.self){ item in
Text(item)
}
.onDelete(perform: deleteItems)
.onMove(perform: moveItems)
}
}
// 删除元素
func deleteItems(at offsets:IndexSet){
items.remove(atOffsets: offsets)
}
// 移动元素
func moveItems(from source:IndexSet, to destination:Int){
items.move(fromOffsets: source, toOffset: destination)
}
}

3.6 下拉刷新
refreshable
支持下拉刷新功能。
swift
struct ListDemoView: View {
@State var items = ["张三","李四","王五","赵六"]
var body: some View {
VStack{
List(items,id: \.self) {item in
Text(item)
}
.refreshable {
await fetchData()
}
}
}
func fetchData() async{
await Task.sleep(2 * 1_000_000_000) // 2 seconds
self.items.append("Orange")
}
}
3.7 设置标题
在SwiftUI
中,navigationTitle
是一个用于设置导航视图中标题的修饰符。这个修饰符通常与 NavigationView
一起使用,以为视图提供一个标题,显示在导航栏的顶部。
navigationTitle
修饰符可以应用于List
或其他视图,以设置当前视图的标题。当视图被嵌入在NavigationView
中时,navigationTitle
会在导航栏中显示。
swift
struct TitleListView: View {
let items = ["Red", "Green", "Blue"]
var body: some View {
NavigationView {
List(items, id: \.self) { item in
Text(item)
}
.toolbar{
EditButton()
}
.navigationTitle("Colors")
}
}
}
注意 :navigationTitle
只有在视图被嵌套在NavigationView
中时才会生效。否则,标题不会显示。
3.8 多选或单选
在 SwiftUI
中,List
组件的 selection
属性用于支持多选或单选功能。通过 selection
属性,我们可以跟踪用户在列表中选择的项。这个功能通常与 EditMode
结合使用,以便用户可以进入编辑模式进行选择。
selection
属性需要绑定到一个状态变量,该变量可以是 Set
类型(用于多选)或单个可选值(用于单选)。当用户在列表中选择或取消选择项时,绑定的变量会自动更新。
3.8.1 多选
swift
struct TitleListView: View {
let items = ["Red", "Green", "Blue"]
@State private var selectedItems = Set<String>()
var body: some View {
NavigationView {
List(items, id: \.self, selection: $selectedItems) { item in
Text(item)
}
.toolbar{
EditButton()
}
.navigationTitle("选择颜色")
}
}
}

3.8.2 单选
如果希望实现单选功能,可以将 selectedItems
改为一个可选值:
swift
struct TitleListView: View {
let items = ["Red", "Green", "Blue"]
@State private var selectedItem: String? = nil
var body: some View {
NavigationView {
List(items, id: \.self, selection: $selectedItem) { item in
Text(item)
}
.toolbar{
EditButton()
}
.navigationTitle("选择颜色")
}
}
}

3.8.3 注意事项
- 编辑模式:
selection
属性的功能通常在列表进入编辑模式后才有效。EditButton
是一个简单的方法来切换编辑模式. - 绑定类型: 对于多选,
selection
应绑定到一个Set
类型的变量;对于单选,selection
应绑定到一个可选值。 - 唯一标识: 列表项需要有唯一标识符(例如通过
id: \.self
),以便SwiftUI
能够正确跟踪选择状态。
四、综合案例
以水果CRUD为例,如下:
swift
import SwiftUI
struct ContentView: View {
@State private var fruits = ["苹果", "香蕉", "橙子", "葡萄"]
@State private var selectedFruits = Set<String>()
@State private var searchText = ""
var body: some View {
NavigationView {
VStack {
// 搜索框
TextField("搜索水果", text: $searchText)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
// 列表
List(selection: $selectedFruits) {
ForEach(filteredFruits, id: \.self) { fruit in
Text(fruit)
}
.onDelete(perform: deleteFruits)
.onMove(perform: moveFruits)
}
.listStyle(InsetGroupedListStyle())
.navigationTitle("水果列表")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
EditButton()
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: addFruit) {
Image(systemName: "plus")
}
}
}
}
}
}
// 过滤水果
var filteredFruits: [String] {
if searchText.isEmpty {
return fruits
} else {
return fruits.filter { $0.contains(searchText) }
}
}
// 添加水果
func addFruit() {
fruits.append("新水果")
}
// 删除水果
func deleteFruits(at offsets: IndexSet) {
fruits.remove(atOffsets: offsets)
}
// 移动水果
func moveFruits(from source: IndexSet, to destination: Int) {
fruits.move(fromOffsets: source, toOffset: destination)
}
}
#Preview {
ContentView()
}
代码说明
-
搜索功能:
- 使用
TextField
来实现简单的搜索功能,用户可以输入文本来过滤水果列表。 filteredFruits
计算属性根据searchText
返回过滤后的水果列表。
- 使用
-
列表功能:
List(selection:)
: 支持多选功能,绑定到selectedFruits
。ForEach
: 用于迭代filteredFruits
,并为每个水果创建一个文本视图。.onDelete
和.onMove:
支持删除和重新排序水果。.listStyle
: 使用InsetGroupedListStyle
来设置列表的外观。
-
导航和工具栏:
NavigationView
和navigationTitle
: 为列表提供导航栏和标题。EditButton
和addFruit
: 提供编辑和添加新水果的功能。