Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List or OutlineGroup expanded by default in SwiftUI

With List or OutlineGroup in SwiftUI how to make some (or all) of their branches expanded by default when creating the view. This seems to be possible with DisclosureGroup with a binding.

This could be useful for restoring state or customizing the view for presentation.

like image 705
João Colaço Avatar asked Jul 10 '20 10:07

João Colaço


People also ask

What is the use of outlinegroup in Swift?

OutlineGroup is meant to be used in Lists within SwiftUI, and as far as list items/rows/cells go you can configure it to have a disclosure indicator of some sorts. In the UIKit world, these would be found on UITableViewCell as AccessoryType and on UICollectionViewListCell as UICellAccessory

How to build an outline view in SwiftUI list view?

We introduced to you two new features for SwiftUI List view in this tutorial. As you can see in the demo, it is very easy to build an outline view or expandable list view. All you need to do is prepare with a correct data model. The List view will handle the rest, traverse the data structure, and render the outline view.

What is inset grouped in SwiftUI list?

In iOS 13, Apple brought a new style to UITableView called Inset Grouped, where the grouped sections are inset with rounded corners. However, this style was not available to the List view in the SwiftUI framework. With the upcoming release of iOS 14, Apple added this new style to SwiftUI list.

What is the use of disclosuregroup in SwiftUI?

The List and OutlineGroup views provide an easy way to group and display hierarchical information to users with minimal coding. The DisclosureGroup view is used by these views to allow users to expand and collapse sections of information, and may also be used directly in your own SwiftUI declarations.


Video Answer


2 Answers

Reusable version of OutlineGroup, where expandability is under control.

import SwiftUI

struct NodeOutlineGroup<Node>: View where Node: Hashable, Node: Identifiable, Node: CustomStringConvertible{
    let node: Node
    let childKeyPath: KeyPath<Node, [Node]?>
    @State var isExpanded: Bool = true

    var body: some View {
        if node[keyPath: childKeyPath] != nil {
            DisclosureGroup(
                isExpanded: $isExpanded,
                content: {
                    if isExpanded {
                        ForEach(node[keyPath: childKeyPath]!) { childNode in
                            NodeOutlineGroup(node: childNode, childKeyPath: childKeyPath, isExpanded: isExpanded)
                        }
                    }
                },
                label: { Text(node.description) })
        } else {
            Text(node.description)
        }
    }
}

struct ContentView: View {
    var body: some View {
        List {
            NodeOutlineGroup(node: data, childKeyPath: \.children, isExpanded: true)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

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 data =
  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: [])
       ])
    ])

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
like image 104
Paul B Avatar answered Oct 16 '22 23:10

Paul B


I was searching for this as well and I believe OutlineGroup doesn't support this. Instead I've moved to DisclosureGroup, which OutlineGroup uses for it's implementation, and directly supports an expansion boolean binding as well as allowing nesting:

struct ToggleStates {
    var oneIsOn: Bool = false
    var twoIsOn: Bool = true
}
@State private var toggleStates = ToggleStates()
@State private var topExpanded: Bool = true

var body: some View {
    DisclosureGroup("Items", isExpanded: $topExpanded) {
        Toggle("Toggle 1", isOn: $toggleStates.oneIsOn)
        Toggle("Toggle 2", isOn: $toggleStates.twoIsOn)
        DisclosureGroup("Sub-items") {
            Text("Sub-item 1")
        }
    }
}

Example from https://developer.apple.com/documentation/swiftui/disclosuregroup

like image 3
Evan Moran Avatar answered Oct 17 '22 00:10

Evan Moran