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.
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
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.
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.
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.
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()
}
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With