A pack of SwiftUI tree pickers that provide selecting options from hierarchical data. Pickers work on iOS, iPadOS and visionOS. Library hasn't third-party dependencies.
TreePicker
package has several tree pickers for different selection value: exactly one selected value, optional value and set of values. Use TreeSinglePicker
, TreeOptionalPicker
and TreeMultiPicker
respectively.
Work with hierarchical data, it's children and selection is similar to SwiftUI hierarchical List
. Additionaly you can specify selection method. Next methods available:
- Only leaves (nodes without children) are selectable.
- All nodes (include folders) are selectable.
- All nodes are selectable and selecting a node automatically selects all its child nodes. This method is available for
TreeMultiPicker
only.
Open .xcproject
file → click PROJECT
→ Package Dependencies
→ +
→ type https://github.com/borisovodov/TreePicker
in the search field → click Add Package
After that add import TreePicker
in your source code.
You create a tree picker by providing a tree-structured data, children
parameter that provides a key path to get the child nodes at any level, selection binding, a label that describes the purpose of selecting an option and a row content. For TreeOptionalPicker
and TreeMultiPicker
you can specify a view that represent empty selection value.
The following example shows how to create a tree picker with the tree of a Location
type that conforms to Identifiable
protocol. Picker provide multiple selection.
struct Location: Hashable, Identifiable {
let id = UUID()
var title: String
var children: [Location]?
}
private let locations: [Location] = [
.init(title: "🇬🇧 United Kingdom", children: [
.init(title: "London", children: nil),
.init(title: "Birmingham", children: nil),
.init(title: "Bristol", children: nil)
]),
.init(title: "🇫🇷 France", children: [
.init(title: "Paris", children: nil),
.init(title: "Toulouse", children: nil),
.init(title: "Bordeaux", children: nil)
]),
.init(title: "🇩🇪 Germany", children: [
.init(title: "Berlin", children: nil),
.init(title: "Hesse", children: [
.init(title: "Frankfurt", children: nil),
.init(title: "Darmstadt", children: nil),
.init(title: "Kassel", children: nil),
]),
.init(title: "Hamburg", children: nil)
]),
.init(title: "🇷🇺 Russia", children: nil)
]
@State private var multiSelection: Set<UUID> = []
var body: some View {
NavigationStack {
Form {
TreeMultiPicker("Location", data: locations, children: \.children, selection: $multiSelection) { location in
Text(location.title)
}
}
}
}
If data
doesn't conform Identifable
protocol when you can specify key path to hashable identifier through id
parameter. For example for Location
like this:
struct Location: Hashable {
var title: String
var children: [Location]?
}
you need to use initializer with id
parameter:
TreeMultiPicker("Location", data: locations, id: \.title, children: \.children, selection: $multiSelection) { location in
Text(location.title)
}
When select a row in a tree, depending on the type of SelectionValue
, either the object itself became selection value or the value of it's identifier.
You can allow all nodes selection or only leaves. For this you need to specify selectionMethod
parameter. By default parameter equal leafNodes
value. It means that only node without children will be selectable. If choose nodes
value (independent
for TreeMultiPicker
), all nodes (include folders) will be selectable. For cascading selection of option children in TreeMultiPicker
you need to use cascading
value. Create multi picker with cascading selection method for example:
TreeMultiPicker("Location", data: locations, children: \.children, selection: $multiSelection, selectionMethod: .cascading) { location in
Text(location.title)
}