I am new to SwiftUI and I am simply experimenting with different NavigationStack options. I have a navigation stack that shows a list of words. When the user clicks on the navigation link it shows a detailed view of that word. Very simple.
The code below doesn't work. When I click on the link, it takes me to the a screen which just flashes and it goes directly to the parent view of the view below.
var body: some View {
NavigationStack {
List(dictionary, id: \.id) { wordDefinition in
NavigationLink(wordDefinition.g_keyword, value: wordDefinition)
}
.navigationDestination(for: DictionaryEntry.self) { wordDefinition in
DefinitionCardView(wordDefinition: wordDefinition)
}
.listStyle(PlainListStyle())
}
}
This code works fine.
var body: some View {
NavigationStack {
List(dictionary, id: \.id) { wordDefinition in
NavigationLink(wordDefinition.g_keyword, destination: DefinitionCardView(wordDefinition: wordDefinition))
}
.listStyle(PlainListStyle())
}
}
Parent view of the above code. I am just playing around with code so please ignore any logic or optimization issues. For example SomeViewThatActuallyDoesNothing() acts like a button that if pressed, takes you to the view in question. But that's just me trying different things and I don't consider this a good design choice. However, this illogical design choice presents the problem I am facing here and curiosity got me. Why does one version work and the other doesn't?
var body: some View {
NavigationStack {
VStack(alignment: .leading) {
SomeViewThatActuallyDoesNothing(searchWord: $searchWord)
.onTapGesture {
isSearchFieldTapped = true;
}
NavigationLink {
DefinitionCardView(wordDefinition: wordOfTheDay)
} label: {
SomeSampleCardView(wordOfTheDay: wordOfTheDay)
}
}
.padding()
.navigationDestination(isPresented: $isSearchFieldTapped) {
MainSearchView() // This is the view with the problem (the code above)
}
}
I am curios now why the first version is not working while the second is fine.
EDIT: Minimal Reproducible Example
import SwiftUI
import SwiftData
struct ContView: View {
var body: some View {
NavigationStack {
VStack(alignment: .center) {
Spacer()
NavigationLink {
MinNOTWorkingListView()
} label: {
Text("A View With a Problem")
}
NavigationLink {
MinWorkingListView()
} label: {
Text("A Working View")
}
Spacer()
NavigationLink {
MinCardView(wordDef: "wordOfTheDay")
} label: {
Text("Some Text")
}
Spacer()
}
.padding()
}
}
}
struct MinWorkingListView: View {
private var wordList: [String] = {
var list: [String] = []
for i in 1...5 {
list.append("Word" + String(i))
}
return list
}()
var body: some View {
NavigationStack {
List(wordList, id: \.self) { wordDefinition in
NavigationLink(wordDefinition, destination: MinCardView(wordDef: wordDefinition))
}
.listStyle(PlainListStyle())
}
}
}
struct MinNOTWorkingListView: View {
private var wordList: [String] = {
var list: [String] = []
for i in 1...5 {
list.append("Word" + String(i))
}
return list
}()
var body: some View {
NavigationStack {
List(wordList, id: \.self) { wordDefinition in
NavigationLink(wordDefinition, value: wordDefinition)
}
.navigationDestination(for: String.self) { wordDefinition in
MinCardView(wordDef: wordDefinition)
}
.listStyle(PlainListStyle())
}
}
}
struct MinCardView: View {
var wordDef: String
var body: some View {
Text(wordDef)
}
}
Just like mentioned in a comment by @Sweeper, you should not nest two
NavigationStacks.Another thing, when mixing
NavigationLink(destination:label:)withNavigationLink(value:label:)like that:..it seems to overwhelm the
NavigationStack(..and it might actually be a bug).Solution:
You can use several
NavigationLink(value:label:)s with dedicated.navigationDestination(for:destination)modifiers for each.Alternatively you could introduce a new
Destinationenum and handle its value in a.navigationDestination(for:destination)with aswitchstatement: