iosswiftmacosswiftui

How to determine how many `NavigationSplitView` columns are visible?


Overview

Questions

  1. In NavigationSplitView how to determine how many columns are visible?
  2. Or how to determine if a view was pushed or not?
  3. Or was the view a slide over (iPad sidebar slides over)?

Background

Reason for asking: I have a sidebarList, contentList and detailList. Now I would like to have different selection of cells depending on how many columns are visible

Sample Code:

struct ContentView: View {
    @State private var departments = ["D1"]
    @State private var employees = ["E1", "E2", "E3"]
    @State private var selectedDepartment: String?
    @State private var selectedEmployee: String?

    var body: some View {
        NavigationSplitView {
            List(departments, id: \.self, selection: $selectedDepartment) { department in
                Text(department)
            }
        } content: {
            List(employees, id: \.self, selection: $selectedEmployee) { employee in
                Text(employee)
            }
        } detail: {
            if let selectedEmployee {
                Text(selectedEmployee)
            } else {
                Text("No employee selected")
            }
        }
    }
}

Solution

  • You can use NavigationSplitViewVisibility structure in the initialiser.

    @State private var columnVisibilty: NavigationSplitViewVisibility = .all
    

    This would be the example for an 3 column design. By reading or changing the state variable you are able to control it. (Therefore the binding, the system sets what it currently is displaying) added for clarity

    NavigationSplitView(columnVisibility: $columnVisibilty) sidebar: {
    ...
    } content: {
    ...
    } detail: {
    ...
    }
    

    Here is the link to Apples docs: https://developer.apple.com/documentation/swiftui/navigationsplitviewvisibility

    Added the crude example:

    struct ContentView: View {
        @State private var columnVisibility: NavigationSplitViewVisibility = .all
        var body: some View {
            NavigationSplitView(columnVisibility: $columnVisibility) {
                Text("Sidebar:")
                    .toolbar {
                        Button("Print") {
                            print(columnVisibility)
                        }
                    }
            } content: {
                Text("Content:")
                    .toolbar {
                        Button("Print") {
                            print(columnVisibility)
                        }
                    }
            } detail: {
                Text("Detail:")
                    .toolbar {
                        Button("Print") {
                            print(columnVisibility)
                        }
                    }
            }
            
        }
    }
    

    This lets me set an initial setting BUT it gets updated with the current status of the SplitView. Just press print button and you can see the changes.