OutlineGroup 是 SwiftUI 中用于展示树状结构数据的视图,它能够递归地渲染层级数据,非常适合展示文件目录、组织结构图等。它与 List
视图类似,但更专注于处理具有父子关系的数据。
OutlineGroup 的使用方式
OutlineGroup 主要通过以下方法使用:
OutlineGroup(data, id: \.id, children: \.children) { item in
// 显示单个 item 的视图
}
data
: 这是一个符合Identifiable
协议的集合,表示树状结构的根节点数据。id
: 一个 KeyPath,用于标识数据中的唯一性,类似于List
中的id
参数。children
: 一个 KeyPath,指向数据中包含子节点的属性。子节点属性必须是可选类型 (Optional
),例如[TreeItem]?
,空值表示该节点是叶子节点。content
: 一个闭包,用于定义如何显示单个节点的视图。
示例
为了更好地理解 OutlineGroup 的使用,我们来看一个具体的例子。假设我们有一个文件目录结构,可以用以下结构体表示:
struct FileItem: Identifiable {
let id = UUID()
let name: String
var children: [FileItem]?
}
然后,我们可以创建一个示例数据:
let fileData = [
FileItem(name: "Documents", children: [
FileItem(name: "Report.pdf"),
FileItem(name: "Design.sketch"),
FileItem(name: "Project", children: [
FileItem(name: "README.md"),
FileItem(name: "main.swift")
])
]),
FileItem(name: "Photos", children: [
FileItem(name: "IMG_001.jpg"),
FileItem(name: "IMG_002.jpg")
])
]
使用 OutlineGroup 展示该数据:
OutlineGroup(fileData, id: \.id, children: \.children) { item in
HStack {
Image(systemName: item.children == nil ? "doc.fill" : "folder.fill")
Text(item.name)
}
}
这段代码会递归地渲染 fileData
中的数据,创建可展开的列表视图。具有子节点的项(例如 “Documents” 和 “Project”)会显示一个 disclosure indicator,点击可以展开或折叠子节点。
与 List 结合使用
OutlineGroup 也可以与 List
结合使用,以获得列表样式的外观。尤其是在侧边栏导航中,这种组合非常实用。
List(fileData, id: \.id, children: \.children) { item in
HStack {
Image(systemName: item.children == nil ? "doc.fill" : "folder.fill")
Text(item.name)
}
}
.listStyle(.sidebar) // 侧边栏样式
进阶用法:自定义 DisclosureGroup
OutlineGroup 内部使用 DisclosureGroup
来实现展开和折叠功能。你可以通过自定义 DisclosureGroup
来实现更精细的控制。
总结
OutlineGroup 提供了一种简洁而强大的方式来展示树状结构数据。通过理解其基本用法和与 List
的结合,你可以轻松地创建具有良好用户体验的层级列表视图。 1 2 4 6
import SwiftUI
struct FileItem: Identifiable {
let id = UUID()
let name: String
var children: [FileItem]?
}
struct ContentView: View {
let fileData = [
FileItem(name: "Documents", children: [
FileItem(name: "Report.pdf"),
FileItem(name: "Design.sketch"),
FileItem(name: "Project", children: [
FileItem(name: "README.md"),
FileItem(name: "main.swift")
])
]),
FileItem(name: "Photos", children: [
FileItem(name: "IMG_001.jpg"),
FileItem(name: "IMG_002.jpg")
])
]
var body: some View {
List(fileData, id: \.id, children: \.children) { item in
HStack {
Image(systemName: item.children == nil ? "doc.fill" : "folder.fill")
Text(item.name)
}
}
.listStyle(.sidebar)
}
}
核心概念 #
OutlineGroup
是 SwiftUI 中用于展示树形层级结构数据的视图容器,特别适合需要展开/折叠交互的场景(如文件目录、分类菜单等)。它自动处理展开状态,并支持递归渲染嵌套数据。以下是使用详解:
- 适用场景:多层级数据(如文件夹结构、分类导航、组织架构)。
- 自动状态管理:用户点击时会自动切换展开/折叠状态,无需手动管理。
- 递归渲染:无需为每一层编写重复代码,自动处理子节点。
基本用法 #
1. 数据结构 #
确保数据模型满足以下条件:
- 遵循
Identifiable
协议(每个元素有唯一标识)。 - 通过某个属性(如
children
)指向子节点(可选数组,nil 表示叶节点)。
struct FileItem: Identifiable {
let id = UUID()
var name: String
var children: [FileItem]? // 非 nil 表示可展开
}
// 示例数据
let fileTree: [FileItem] = [
FileItem(name: "文档", children: [
FileItem(name: "工作", children: [
FileItem(name: "项目1.pdf", children: nil),
FileItem(name: "报告.doc", children: nil)
]),
FileItem(name: "个人", children: [
FileItem(name: "照片", children: [...]),
])
])
]
2. 创建 OutlineGroup #
在 List
或 OutlineGroup
中直接使用:
List {
OutlineGroup(fileTree, children: \.children) { item in
Text(item.name)
.padding(.leading, 8)
}
}
.listStyle(.sidebar) // 可选样式(如侧边栏风格)
高级用法 #
自定义展开图标 #
通过 Label
和系统图标增强交互提示:
OutlineGroup(fileTree, children: \.children) { item in
Label {
Text(item.name)
} icon: {
Image(systemName: item.children != nil ? "folder" : "doc")
}
}
控制展开状态 #
手动管理展开状态(需使用 IdentifiedArray
等可标识集合):
@State private var expandedIDs: Set<UUID> = []
OutlineGroup(fileTree, children: \.children, id: \.id, expanded: $expandedIDs) { item in
// ...
}
结合 DisclosureGroup #
混合使用实现更复杂交互(如添加自定义按钮):
OutlineGroup(fileTree, children: \.children) { item in
DisclosureGroup {
// 子内容
} label: {
Text(item.name)
Button("更多") { /* ... */ }
}
}
对比 DisclosureGroup #
OutlineGroup
:自动递归、适合动态层级数据。DisclosureGroup
:手动控制单个展开状态、适合固定层级。
示例效果 #
会渲染为类似系统的文件浏览器,用户点击文件夹图标可展开/折叠子项,列表自动适应层级缩进。
注意事项 #
- 数据不可变:直接修改
children
可能不触发更新,建议使用@State
或绑定到可观察对象。 - 性能优化:极深层级数据考虑使用
LazyVStack
或分页加载。 - 样式调整:通过
.listRowInsets
或.indentationLevel
控制缩进。
通过 OutlineGroup
可以快速实现复杂的树形交互界面,减少状态管理代码,提升开发效率。