SwiftUI NavigationView jumps back and forth with NavigationLink in ForEach inside List

Viewed 890

I am attempting to including a dynamic list of navigation links within each row of a List in a NavigationView. Whenever I tap one of the links though, the navigation jumps back and forth several times.

What is causing the back and forth navigation? And is it possible to express this pattern in some other way with SwiftUI to avoid this issue?

import SwiftUI

struct MonthData: Hashable, Codable, Identifiable {
    var id: Int
    var name: String
    var tasks: [TaskData]
}

struct TaskData: Hashable, Codable, Identifiable {
    var id: Int
    var name: String
}

let months: [MonthData] = [
    MonthData(id: 1, name: "January", tasks: []),
    MonthData(id: 2, name: "February", tasks: [
        TaskData(id: 21, name: "Do something"),
        TaskData(id: 22, name: "Do something else")
    ])
]

struct FooView: View {
    var body: some View {
        NavigationView {
            List(months) { month in
                VStack {
                    ForEach(month.tasks) { task in
                         NavigationLink(
                            destination: Text(task.name)
                       ) {
                           Text(task.name)
                       }
                    }
                }
            }
            .navigationBarTitle(Text("Months"))
        }
    }
}

struct FooView_Previews: PreviewProvider {
    static var previews: some View {
        FooView()
    }
}
2 Answers

It is going back and forth because in your example for January there is no link on the cell since there are no tasks for January. On the other hand, for February there are two navigation links (one per task) and that's why it goes in and out. You need to think about your layout and navigation first. But eventually you need to add one item for each cell and some cells may navigate and some may not depending on your logic. But there should be a maximum of one navigation link per list item. This post may help: SwiftUI - nested list

Here is fixed variant. Tested with Xcode 12 / iOS 14.

struct FooView: View {
    var body: some View {
        NavigationView {
            List {
                ForEach(months) { month in
                    Section {
                        ForEach(month.tasks) { task in
                            NavigationLink(
                                destination: Text(task.name)
                            ) {
                                Text(task.name)
                            }
                        }
                    }
                }
            }
            .navigationBarTitle(Text("Months"))
        }
    }
}
Related