Here is a very simple example, just to show how to use hierarchical List
struct FileItem: Identifiable {
let name: String
var children: [FileItem]?
var id: String { name }
}
struct ContentView: View {
@State var data: [FileItem] = [FileItem(name: "First", children: [FileItem(name: "child1"), FileItem(name: "child2")])] // State, so that you can modify
var body: some View {
List(data, children: \.children, rowContent: { Text($0.name) })
}
}
In Xcode documentation (searching for List), you will find more details on how to use hierarchical lists:
Creating hierarchical lists
You can also create a hierarchical list of arbitrary depth by providing tree-structured data and a children parameter that provides a key path to get the child nodes at any level. The following example uses a deeply-nested collection of a custom FileItem type to simulate the contents of a file system. The list created from this data uses collapsing cells to allow the user to navigate the tree structure.
struct ContentView: View {
struct FileItem: Hashable, Identifiable, CustomStringConvertible {
var id: Self { self }
var name: String
var children: [FileItem]? = nil
var description: String {
switch children {
case nil:
return "📄 \(name)"
case .some(let children):
return children.isEmpty ? "📂 \(name)" : "📁 \(name)"
}
}
}
let fileHierarchyData: [FileItem] = [
FileItem(name: "users", children:
[FileItem(name: "user1234", children:
[FileItem(name: "Photos", children:
[FileItem(name: "photo001.jpg"),
FileItem(name: "photo002.jpg")]),
FileItem(name: "Movies", children:
[FileItem(name: "movie001.mp4")]),
FileItem(name: "Documents", children: [])
]),
FileItem(name: "newuser", children:
[FileItem(name: "Documents", children: [])
])
]),
FileItem(name: "private", children: nil)
]
var body: some View {
List(fileHierarchyData, children: \.children) { item in
Text(item.description)
}
}
}
Here is a simple remove implementation:
struct ContentView: View {
@State var data: [FileItem] = [FileItem(name: "First", children: [FileItem(name: "child1"), FileItem(name: "child2")])]
var body: some View {
List(data, children: \.children) { item in
HStack {
Text(item.name)
// If there are children, we cannot remove it
if item.children == nil || item.children!.isEmpty {
Spacer()
Button("Remove"){
// This is a simple implementation if only children, no grandChildren
// if grandchildren, need to have a recursive search for the parent
for (index, parent) in data.enumerated() {
// If it is children
if parent.children != nil && !parent.children!.isEmpty {
for child in parent.children! {
if child.name == item.name {
var newChildren = parent.children!
newChildren.removeAll(where: { $0.name == item.name })
data[index].children = newChildren
print("remove \(item.name)")
}
}
} else {
// It is the parent
for (index, parent) in data.enumerated() {
data.remove(at: index)
print("remove \(item.name)")
}
}
}
}
}
}
}
}
}
Don't forget to close the thread if that's OK. Otherwise, explain where the problem is.