SwiftUI应用跳转ResultView后自动返回前视图的原因及修复方案
SwiftUI导航跳转异常:ResultView自动返回的原因与修复
功能流程
- 用户在
AddressInputView的输入框中填写地址 - 提交后,应用跳转到
ResultView并传递地址数据
问题现象
点击提交后,ResultView只闪一下就自动跳回AddressInputView,无法正常停留。
核心原因
你代码里存在多层嵌套的NavigationStack,这是导致导航状态混乱的根本原因:
StartView已经创建了一个顶层NavigationStackAddressInputView内部又套了一个独立的NavigationStackResultView里还再嵌套了第三个NavigationStack
SwiftUI的导航栈是层级式管理的,多层嵌套会让系统无法正确维护导航状态,触发自动回退的异常。
另外还有两个次要问题:
ResultView里用的@Environment(\.presentationMode)在iOS 16+已经被@Environment(\.dismiss)替代ResultView的初始化写法冗余,没必要手动处理projectedValue
修复方案
关键:移除多余的NavigationStack
只保留最外层StartView的NavigationStack,把导航逻辑统一交给顶层栈管理,移除AddressInputView和ResultView内部的NavigationStack。
修复后的完整代码
StartView.swift
struct StartView: View { @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { AddressInputView(path: $path) .navigationDestination(for: Destination.self) { destination in switch destination { case .result(let address, let experiences): ResultView(address: address, experiences: experiences) } } } } } // 统一管理导航目标,实现Hashable才能被导航栈识别 enum Destination: Hashable { case result(address: String, experiences: [Experience]) }
AddressInputView.swift
struct AddressInputView: View { @State private var address: String = "" @State private var experiences: [Experience] = [] @Binding var path: NavigationPath var body: some View { VStack(spacing: 16) { TextField("", text: $address, prompt: Text("Search address")) .textFieldStyle(.roundedBorder) .onSubmit { path.append(Destination.result(address: address, experiences: experiences)) } Button("Submit") { path.append(Destination.result(address: address, experiences: experiences)) } .buttonStyle(.borderedProminent) } .padding() } }
ResultView.swift
struct ResultView: View { let address: String let experiences: [Experience] // 仅展示数据时用常量即可,无需绑定 init(address: String, experiences: [Experience]) { self.address = address self.experiences = experiences } var body: some View { ScrollView { VStack(alignment: .leading, spacing: 12) { Text("Results for: \(address)") .font(.title) ForEach(experiences, id: \.name) { experience in ResultTile(experience: experience) } } .padding() } .navigationTitle("Results") } }
额外优化建议
- 如果后续需要在
ResultView中修改原地址或experiences数据,再把参数改成@Binding,否则用常量传递更高效 - 给输入框和按钮添加基础样式,提升界面美观度
- 建议给
Experience结构体实现Identifiable协议,或者在ForEach中使用唯一id(比如\.id),避免名称重复导致的渲染异常
内容的提问来源于stack exchange,提问作者Timo Ernst
相关产品推荐
相关产品推荐

