Question

How can I create a SwiftUI List with expandable child views in the second layer?

Answer and Explanation

Creating a SwiftUI List with expandable child views in the second layer involves using a combination of `List`, `DisclosureGroup`, and state management. Here's a breakdown of how you can achieve this:

1. Data Structure:

- First, define a data structure that represents your hierarchical data. This structure should include a way to represent parent-child relationships and whether a group is expanded or not. For example:

struct Item: Identifiable {
  let id = UUID()
  let name: String
  var children: [Item]?
}

2. State Management:

- Use `@State` variables to manage the expansion state of each `DisclosureGroup`. You can use a dictionary to store the expansion state for each item's ID.

3. SwiftUI List and DisclosureGroup:

- Use a `List` to display the top-level items. Inside the `List`, use `DisclosureGroup` to create expandable sections for items with children. Here's an example:

struct ContentView: View {
  @State private var items: [Item] = [
    Item(name: "Parent 1", children: [
      Item(name: "Child 1.1"),
      Item(name: "Child 1.2")
    ]),
    Item(name: "Parent 2", children: [
      Item(name: "Child 2.1"),
      Item(name: "Child 2.2", children: [
        Item(name: "Grandchild 2.2.1")
      ])
    ])
  ]
  @State private var expandedItems: [UUID: Bool] = [:]

  var body: some View {
    List {
      ForEach(items) { item in
        DisclosureGroup(isExpanded: Binding(get: { expandedItems[item.id, default: false] }, set: { expandedItems[item.id] = $0 })) {
          Text(item.name)
        } content: {
          if let children = item.children {
            ForEach(children) { child in
              if let grandChildren = child.children {
                DisclosureGroup(isExpanded: Binding(get: { expandedItems[child.id, default: false] }, set: { expandedItems[child.id] = $0 })) {
                  Text(child.name)
                } content: {
                  ForEach(grandChildren) { grandChild in
                    Text(grandChild.name).padding(.leading, 20)
                  }
              }
                           } else {
              Text(child.name).padding(.leading, 20)
            }
            }
          }
        }
      }
    }
  }
}

4. Explanation:

- The `Item` struct defines the structure of your data, including an optional array of child items.

- The `expandedItems` dictionary keeps track of which `DisclosureGroup` is expanded using the item's ID as the key.

- The `List` iterates through the top-level items. For each item, a `DisclosureGroup` is created. The `isExpanded` binding is used to control the expansion state of the group.

- If an item has children, another `ForEach` loop is used to display them. The children are indented using `padding(.leading, 20)` for visual hierarchy.

- If a child has grand children, another `DisclosureGroup` is created to display them.

5. Customization:

- You can customize the appearance of the list and the `DisclosureGroup` using SwiftUI modifiers.

By following these steps, you can create a SwiftUI List with expandable child views in the second layer, allowing users to navigate hierarchical data effectively.

More questions