SwiftUI NavigationDestination跳转异常问题求助
问题原因
你遇到的异常是因为在同一个NavigationStack中混合使用了两种不同的导航机制:ContentView里用的是旧版闭包式NavigationLink,而HeroList里用的是新版value + navigationDestination导航方式,导致导航栈状态管理冲突,出现视图闪回、返回时错误跳转的现象。
解决方案
以下三种方案都能解决该问题,可根据实际需求选择:
方案一:统一使用新版路径式导航
定义导航枚举管理所有跳转目标,在整个导航栈中统一使用value + navigationDestination机制:
import SwiftUI // 定义导航路径枚举 enum NavTarget { case heroList case heroDetail(Hero) } struct ContentView: View { @State private var navPath = NavigationPath() var body: some View { NavigationStack(path: $navPath) { Button("Click here to see the list of heroes") { navPath.append(NavTarget.heroList) } .navigationDestination(for: NavTarget.self) { target in switch target { case .heroList: HeroList(navPath: $navPath) case .heroDetail(let hero): HeroView(hero: hero) } } } } } struct HeroList: View { @Binding var navPath: NavigationPath @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 Button("Find out more about: \(hero.name)") { navPath.append(NavTarget.heroDetail(hero)) } .padding(.bottom) } } } } struct HeroView: View { @ObservedObject var hero: Hero var body: some View { Text(hero.name) .font(.title) } } 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)) } }
方案二:HeroList改用闭包式NavigationLink
放弃新版navigationDestination机制,在HeroList中直接使用旧版闭包式跳转,和ContentView保持一致:
import SwiftUI 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 NavigationLink { HeroView(hero: hero) } label: { Text("Find out more about: \(hero.name)") .padding(.bottom) } } } } } struct HeroView: View { @ObservedObject var hero: Hero var body: some View { Text(hero.name) .font(.title) } } 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)) } }
方案三:将Hero改为struct类型(推荐)
当前Hero类没有需要发布的属性,改用值类型struct更符合SwiftUI设计理念,同时避免引用类型带来的导航匹配问题:
import SwiftUI 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) { Text("Find out more about: \(hero.name)") .padding(.bottom) } } } .navigationDestination(for: Hero.self) { hero in HeroView(hero: hero) } } } struct HeroView: View { let hero: Hero var body: some View { Text(hero.name) .font(.title) } } // 改为struct类型 struct Hero: Identifiable, Hashable { let id: Int var name: String }
内容的提问来源于stack exchange,提问作者Samuel Davies
相关产品推荐
相关产品推荐

