SwiftUI基础组件之List详解

文章目录

    • 一、简介
    • 二、基本用法
      • [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: 提供编辑和添加新水果的功能。
相关推荐
小洋人最happy18 小时前
SwiftUI基础组件之HStack、VStack、ZStack详解
swiftui·vstack·zstack·hstack·spacing
coooliang1 天前
【iOS】SwiftUI状态管理
ios·swiftui·swift
卷卷的小趴菜学编程1 天前
c++进阶———继承
java·服务器·c语言·开发语言·c++·list
xxxmine2 天前
跳表(Skip List)详解
java·数据结构·list
dsq_MaDing2 天前
Java 中 List、Set、Map 核心实现类解析
java·开发语言·list
海岸星的清风2 天前
内核数据结构用法(2)list
数据结构·list
liuhuapeng03042 天前
传入一个list map,寻找最大的key和对应的vlaue
java·list
煜3642 天前
List模拟实现
数据结构·list
敢嗣先锋2 天前
鸿蒙5.0实战案例:基于List和Scroller由简单到复杂列表布局开发实践
list·移动开发·多线程·harmonyos·arkui·组件化·鸿蒙开发