Samuel Davies
Samuel Davies

Reputation: 152

SwiftUI NavigationDestination appends View so it is before the current active View

In the code below when i press on a NavigationLink to go to a HeroView, I get an unexpected result. The view is temporarily added and then removed. When i go back from the HeroList to go to ContentView, it navigates to the HeroView i expected to reach from clicking on a hero in the HeroList View.

The example code below recreates this problem. Any help would be greatly appreciated.

struct ContentView: View {
    var body: some View {
        NavigationStack {
            NavigationLink("Click here to see the list of heroes") {
                HeroList()
            }
        }
    }
}
struct HeroList: View {
    @State private var heroes: [Hero] = [Hero(id: 0, name: "Hercules"), Hero(id: 1, name: "Superman")]
    
    var body: some View {
        ScrollView {
            ForEach(heroes, id:\.id) { hero in
                NavigationLink(value: hero) {
                    // Problem happens when the navigation link is pressed
                    Text("Find out more about: \(hero.name)")
                        .padding(.bottom)
                }
            }
        }
        .navigationDestination(for: Hero.self) { hero in
            HeroView(hero: hero)
        }
    }
}
struct HeroView: View {
    @ObservedObject var hero: Hero
    var body: some View {
        Text(hero.name)
            .font(.title)
    }
}
// Custom Hero type
class Hero: Identifiable, Hashable, ObservableObject {
    let id: Int
    var name: String
    
    init(id: Int, name: String) {
        self.id = id
        self.name = name
    }
    
    static func == (lhs: Hero, rhs: Hero) -> Bool {
        return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(ObjectIdentifier(self))
    }
}

Upvotes: 0

Views: 372

Answers (1)

Try this approach using two navigationDestination, one for the HeroList() and another one for the HeroView(...). Also simplified the struct Hero:

struct ContentView: View {
    var body: some View {
        NavigationStack {
            NavigationLink(value: "HeroList") {
                Text("Click here to see the list of heroes")
            }
            .navigationDestination(for: String.self) { _ in   // <-- here
                HeroList()
            }
        }
    }
}

struct HeroList: View {
    @State private var heroes: [Hero] = [Hero(id: 0, name: "Hercules"), Hero(id: 1, name: "Superman")]
    
    var body: some View {
        ScrollView {
            ForEach(heroes) { hero in
                NavigationLink(value: hero) {
                    Text("Find out more about: \(hero.name)")
                        .padding(.bottom)
                }
            }
        }
        .navigationDestination(for: Hero.self) { hero in
            HeroView(hero: hero)
        }
    }
}

struct HeroView: View {
    var hero: Hero   // <-- here
    
    var body: some View {
        Text("-----HeroView-----")
        Text(hero.name).font(.title)
    }
}

struct Hero: Identifiable, Hashable {  // <-- here
    let id: Int
    var name: String
}

Upvotes: 1

Related Questions