What’s New in SwiftUI Lists for iOS 14?

Nested or expandable lists and a brand new view modifier

Lists are a vital component of every application, and SwiftUI List only simplified the way in which we populate our data, typically by conforming to the Identifiable protocol — which ensures each row is unique for dynamic items.

WWDC 2020 paved the way for a few interesting updates to SwiftUI Lists in iOS 14. Let’s look at them.

SwiftUI New Nested Lists Using ‘.children’ Key Path

Up until now, creating nested or expandable lists in SwiftUI required nesting ForEach loops within each other.

The latest iteration of SwiftUI makes building nested lists a whole lot easier by introducing a .children key-path argument in its initialiser. In doing so, it allows us to create recursive outlined SwiftUI lists that show up in a system-standard styling way on iOS, iPadOS, and macOS.

Let’s set up a data structure for our new SwiftUI outlined lists.

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

Now, you could populate data using JSON or any assets file, but for the sake of simplicity, we’ll set a few dummy strings and SF symbols. Let’s do that by conforming our class to ObservableObject — a type of object that announces changes through a publisher.

public class DataFetcher: ObservableObject {
@Published var dataModel = [DataModel]()
init() {
var nestedMenu : [DataModel] = []
for i in 0...5 {
nestedMenu.append(DataModel(name: "Sub Item \(i)", icon: "calendar"))
}
self.dataModel = [
DataModel(name: "Item 1", icon: "book.circle", children: [DataModel(name: "Sub Item 1", icon: "tv.fill", children: [DataModel(name: "Double Sub Item 1", icon: "headphones")])]),
DataModel(name: "Item 2", icon: "printer"),
DataModel(name: "Item 3", icon: "wifi"),
DataModel(name: "Item 4", icon: "person.circle", children: nestedMenu),
DataModel(name: "Item 5", icon: "hand.raised", children: nestedMenu),
DataModel(name: "Item 6", icon: "zzz", children: nestedMenu)
]
}
}

Now that our data source is ready, let’s plug it into our SwiftUI’s View.

struct ContentView: View {
@ObservedObject var fetcher = DataFetcher()
var body: some View {
List(fetcher.dataModel, children: \.children){
item in
HStack{
Image(systemName: item.icon)
Text(item.name)
}
}
}
}

The children key path ensures the list builds out its content in a recursive way (provided the data model is valid).

New ‘listStyle’ Modifier

SwiftUI List provides a listStyle() to customise the look and feel.

You can pass GroupedListStyle() to get an iOS 12–like grouping or InsetGroupedListStyle() to get the iOS 13 and above look with rounded corners.

Here’s a glimpse of how the latter one looks with the above SwiftUI list:

There’s also a SidebarListStyle() that’s useful in iPadOS and macOS, especially for document-based apps that leverage sidebars.

SwiftUI Outline Lists With NavigationLink

When using the SidebarListStyle and embedding the List in a NavigationView, only the rows, with no child are navigatable to NavigationLink’s destination view. SwiftUI takes care of this automatically on iPadOS and macOS as shown below:

But running the same on an iOS device, it’s a little buggy(at the time of writing). Or perhaps, it’s not intended to use in that way:

As you can see, on an iOS device, it shows double disclosures. And despite having child lists, NavigationLink is working which ideally shouldn’t be the case. Hopefully, this bug gets fixed soon.

Conclusion

We saw two cool new updates from the second iteration of SwiftUI that works on iOS 14 and Xcode 12 and above.

That’s it for this one. Thanks for reading.