swiftswiftuixcode13ios15

NavigationLink inside .searchable does not work


I understand its new, but this seems like pretty basic functionality that is not here. When implementing a .searchable in the new iOS 15, it would seem that a NavigationLink does not work, at all.

Ideally, the searchable would produce a filtered list with a ForEach and for each item, a Nav Link could take you to another view based on your selection. The ForEach and list works and looks beautiful, it just wont take you anywhere.

Watching WWDC21, they talk an awful lot about .searchable, but very little demonstration/example is given..

Here is a simple example, with no ForEach loop, that shows it does not work at all.. Am I missing something?

Any insight appreciated:

import SwiftUI

struct ContentView: View {
    
    @State private var term = ""
    
    var body: some View {
        NavigationView {
            Text("Hello, world!")
                .padding()
        }
        .searchable(text: $term) {
            NavigationLink(destination: SecondView()) {
                Text("Go to second view")
            }
        }
    }
}

struct SecondView: View {
    var body: some View {
        Text("Goodbye!")
            .padding()
    }
}

Solution

  • NavigationLink must always be inside NavigationView, no matter what. If you want to put it outside, like inside .searchable, you should use programmatic navigation with isActive.

    struct ContentView: View {
        
        @State private var term = ""
        @State private var isPresenting = false
        
        var body: some View {
            NavigationView {
                
                /// NavigationView must only contain 1 view
                VStack {
                    Text("Hello, world!")
                        .padding()
                    
                    /// invisible NavigationLink
                    NavigationLink(destination: SecondView(), isActive: $isPresenting) { EmptyView()}
                }
            }
            .searchable(text: $term) {
                Button { isPresenting = true } label: {
                    Text("Go to second view")
                }
            }
        }
    }
    
    struct SecondView: View {
        var body: some View {
            Text("Goodbye!")
                .padding()
        }
    }
    

    Result:

    Working navigation link that only appears when search bar tapped