Search code examples
swiftuiswiftui-list

SwiftUI List selected item in composed List


I am building a File Manager app.

In this App the user can select a specific Folder in a list. There is also the possibility to select the option "All Folders" that is the first element in the list.

I want to keep the selected folder in a AppState class, setting it to nil if the user is selecting "All Folders":

class AppState: ObservableObject {
    @Published var selectedFolder: Folder?
}
struct FileListView: View {
    @EnvironmentObject
    var appState: AppState
    
    var body: some View {
        List() {
            FileRowView(
                title: "All Files",
            )
            .onTapGesture {
                appState.selectedFolder = nil
            }
            
            ForEach(filesList) {
                file in
                FileRowView(
                    title: file.title ?? "File unnamed",
                )
                .onTapGesture {
                    appState.selectedFolder = folder
                }
            }
        }
    }
}

Even though this code works and selectedFolder is updated, the List does not highlight in the View actual selected element. It does not have this "bluish" look and feel usually applied to selected items in a list.


Solution

    1. You need the List version that keeps track of selections: List(selection: ).
    2. Even though the binding selection var is optional, you cannot use nil for a List element. nil to the List means that nothing is selected.
    3. With that List initializer you don't need onTapGesture, just give each row a .tag() of the same type as your selection var.

    here is a simplified example:

    struct FileListView: View {
        @State var selectedFolder: Int?
        
        var body: some View {
            List(selection: $selectedFolder) {
                Text("All Files")
                    .tag(999)
                
                ForEach(0..<10) { file in
                    Text("file \(file)")
                        .tag(file)
                }
            }
        }
    }