Selection Parameter in List Initializers

I've got a SwiftUI application on MacOS with a view that is a List. When the user selects an element in the list, I want the contents of another view to change based on what's selected in the List. (Like in the Mac version of the Landmarks app in the SwiftUI On All Devices talk at WWDC.)


Some List initializers have a selection: parameter, but I can't find any documentation on how it works. I've been through all of the SwiftUI tutorials, but they're all for iOS, and don't seem to address this topic = they use NavigationView and NavigationLink, which don't seem applicable on MacOS.


Can someone point me at some documentation for how the selection: parameter to List initializers is supposed to work? Can anyone tell me where to find the source for the Landmarks app used in the SwiftUI On All Devices talk? (Or really, anything else I can look at to figure out how to make this work?)

Replies

I made this little app based on a post in StackOverflow:


struct SomeName : Identifiable, Hashable {

let id = UUID()

let name: String

}


var someNames = [

SomeName(name: "Ron Swanson"),

SomeName(name: "April Ludgate"),

SomeName(name: "Andy Dwyer"),

SomeName(name: "Leslie Knope"),

SomeName(name: "Tom Havaford"),

SomeName(name: "Jerry Gergich")

]


struct ContentView : View {

@State var selectKeeper: SomeName?


var body: some View {

List(someNames, id: \.self, selection: $selectKeeper) { someName in

Text(someName.name)

}.frame(width: 500, height: 460)

}

}


When I run this and click on one of the names, it will highlight, so I assume it's getting selected. I deleted "id; \.self" thinking it was redundant given that SomeName is Identifiable, and it stopped working. I then added "id: \.self" to the List in SomeObjectView in this post:


https://forums.developer.apple.com/thread/122140


Once I did that, that little app started working! So somehow, the "id: \.self" is key. Does anyone understand why?

The key, which wasn't obvious to me at the start, was to ensure that the selection binding value was to an Optional. Also, on iOS and tvOS, the list needs to be in edit mode before selection will be allowed.


Here's a quick example, on iOS:


struct ContentView: View {
    private static let values = [
        "Hello",
        "Γειά σας",
        "Sho'daache",
        "Helô",
        "Здравствуйте!",
    ]

    @State private var selection: String? = nil

    var body: some View {
        VStack {
            HStack {
                Spacer()
                EditButton()
            }
            .padding([.horizontal, .top])

            Text(selection ?? "No Selection")
                .font(.headline)
            Divider()

            List(Self.values, id: \.self, selection: $selection) {
                Text($0)
            }
        }
    }
}

Thanks. Making the selection binding value be an Optional makes some kind of sense.


My guess about the id: parameter is that the id is saved for each entry in the list and used as the selection value. Thus it must match the type of the selection: argument.