Search code examples
swiftswiftuiswiftui-listswiftui-navigationlinkswiftui-navigationview

How do I have a SwiftUI navigation link selected when you open the app


I have created a sample project to explain this better.

When you open the settings app on iPad, the right side of the screen shows the general settings and the left side shows the general settings navigation link selected

Image of settings app

But when people open my app on the right side of the screen is the “Hello” page but on the left, the hello navigation link is not selected

Image of my app

My code:


import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            PrimaryView()
            HelloView()
        }
    }
}

struct PrimaryView: View {
    var body: some View {
        List {
            NavigationLink("Hello", destination: HelloView())
            NavigationLink("World", destination: WorldView())
        }
        .listStyle(InsetGroupedListStyle())
    }
}

struct HelloView: View {
    var body: some View {
        List {
            Text("Hello")
        }.navigationTitle("Hello")
    }
}

struct WorldView: View {
    var body: some View {
        List {
            Text("World")
        }.navigationTitle("World")
    }
}

I tried to find the answer to this on Google, but I probably just didn’t know the right keywords

Thanks in advance :)


Solution

  • First you have to select the starting navigationLink programmatically. For that you have to choose another initializer for the NavigationLink.

    public init <V> (destination: Destination, tag: V, selection: Binding <V?>, @ViewBuilder label: () -> Label) where V: Hashable
    

    Which give :

    NavigationLink("Hello", destination: HelloView(), tag: 1, selection: $selectedLink)
    

    where selectedLink is a @State or a @Binding. Here we will choose a @Binding :

    @Binding var selectedLink: Int?
    

    because the selectedLink will also be changed/"initialized" on the first display of the NavigationView. And this NavigationView is higher in the view hierarchy :

    struct ContentView: View {
        @State private var selectedLink: Int?
    
        var body: some View {
            NavigationView {
                PrimaryView(selectedLink: $selectedLink)
                HelloView()
            }
            .onAppear {
                selectedLink = 1
            }
        }
    }
    
    struct PrimaryView: View {
        @Binding var selectedLink: Int?
        var body: some View {
            List {
                NavigationLink("Hello", destination: HelloView(), tag: 1, selection: $selectedLink)
                    
                NavigationLink("World", destination: WorldView(), tag: 2, selection: $selectedLink)
            }
            
            .listStyle(InsetGroupedListStyle())
            
        }
    }
    

    Now we must force the highlighting of the NavigationLink, at the start (and as long as it is selected) For this we can use listRowBackground:

    NavigationLink("Hello", destination: HelloView(), tag: 1, selection: $selectedLink)
                    .listRowBackground(selectedLink == 1 ? Color(UIColor.systemGray4) : Color.clear)