Expanding lists can be used to display hierarchical structures within a list. Each list item can be expanded to view its contents. The expanding ability is achieved by creating a struct that holds some information and an optional array of items of the same type as the struct itself. Let's examine how expanding lists work by creating an app that displays the contents of a backpack.
Getting ready
Create a new SwiftUI app and name it UsingExpandingLists
.
How to do it…
We start by creating the Backpack
struct that describes the properties of the data we want to display. We'll then create a number of Backpack
constants and display the hierarchical information using a List
view containing a children
property.
The steps are as follows:
- At the bottom of the
ContentView.swift
file, define a Backpack
struct that has an id
, name
, icon
, and content
property. The content
property's type should be an optional array of Backpack
structs:struct Backpack: Identifiable {
let id = UUID()
let name: String
let icon: String
var content: [Backpack]?
}
- Below the
Backpack
struct declaration, create three variables: two currency types and an array of currencies:let dollar = Backpack(name: "Dollar", icon: "dollarsign. circle")
let yen = Backpack(name: "Yen",icon: "yensign.circle")
let currencies = Backpack(name: "Currencies", icon: "coloncurrencysign.circle", content: [dollar, yen])
- Create a
pencil
, hammer
, paperclip
, and glass
constant:let pencil = Backpack(name: "Pencil",icon: "pencil. circle")
let hammer = Backpack(name: "Hammer",icon: "hammer")
let paperClip = Backpack(name: "Paperclip",icon: "paperclip")
let glass = Backpack(name: "Magnifying glass", icon: "magnifyingglass")
- Create a
bin Backpack
constant that contains paperclip
and glass
, as well as a tool
constant that holds pencil
, hammer
, and bin
:let bin = Backpack(name: "Bin", icon: "arrow.up.bin", content: [paperClip, glass])
let tools = Backpack(name: "Tools", icon: "folder", content: [pencil, hammer,bin])
- Going back to the
ContentView
struct, add an instance property; items
, which contains an array of two items, the currencies
and tools
constants defined earlier:struct ContentView: View {
let items = [currencies,tools]
…
}
- Within the
body
variable, replace the Text
view with a List
view that displays the content of the items
array: var body: some View {
List(items, children: \.content){ row in
Image(systemName: row.icon)
Text(row.name)
}
}
The resulting Xcode live preview should look as follows when expanded:
Figure 2.16 – Using expanding lists
Run the Xcode live preview and click on the arrows to expand and collapse the views.
How it works…
We start by creating a struct of the proper format for expanding lists. Expanding lists require one of the struct properties to be an optional array of the same type as the struct itself. Our Backpack
content property holds an optional array of Backpack
items:
struct Backpack: Identifiable {
let id = UUID()
let name: String
let icon: String
var content: [Backpack]?
}
The UUID()
function generates a random identifier and stores it in the id
property. We can manually provide the name
, icon
, and content
variables for the items we add to the backpack.
We create our first hierarchical structure by creating the Dollar
and Yen
variables:
let dollar = Backpack(name: "Dollar", icon: "dollarsign. circle")
let yen = Backpack(name: "Yen",icon: "yensign.circle")
Observe that no content
property has been provided for both variables. This is possible because the content is an optional parameter.
We then create a currencies
constant that that has name
and icon
. The Dollar
and Yen
variables created earlier are added to its content
array.
We use a similar composition to add elements to our tool
constant.
After setting up the data we want to display, we create an item
property in our ContentView
struct that holds an array of Backpack
constants created earlier:
let items = [currencies,tools]
Finally, we replace the Text
view in the ContentView
body with a List
view that iterates over the items. The list is made expandable by adding the children
parameter, which expects an array of the same time as the struct passed to the List
view.
There's more…
The tree structure used for expandable lists can also be generated on a single line, as follows:
let tools = Backpack(name: "Tools", icon: "folder", content:
[Backpack(name: "Pencil",icon: "pencil.circle"),
Backpack(name: "Hammer",icon: "hammer"),
Backpack(name: "Bin", icon: "arrow.up.bin", content:
[Backpack(name: "Paperclip",icon: "paperclip"),
Backpack(name: "Magnifying glass", icon: "magnifyingglass")
])
])
The SwiftUI List
view provides out-of-the-box support for OutlineGroup
in iOS 14. OutlineGroup
computes views and disclosure groups on demand from an underlying collection.
See also
Refer to the WWDC20 video on stacks, grids, and outlines at https://developer.apple.com/videos/play/wwdc2020/10031/.
Refer to the Apple documentation on OutlineGroup
at https://developer.apple.com/documentation/swiftui/outlinegroup.