SwiftUI中导航目标视图调用dismiss()行为不符预期的疑问
问题分析与误解点解析
核心误解点
1. 混淆「视图组合层级」与「导航栈层级」
你在navigationDestination的闭包里直接并列了Text("NavDest: Text-1")和SelectEntry,这两个视图是组合在同一个导航栈条目中的(SwiftUI会自动用VStack包裹它们),并非两个独立的导航页面。SelectEntry和ShowAccounts只是该导航页面的子视图,没有触发新的导航栈层级,因此它们和Text属于同一个导航栈节点。
2. 对presentationMode.dismiss()的作用范围理解错误
presentationMode.dismiss()的作用是关闭当前视图所在的整个导航栈条目。由于ShowAccounts、SelectEntry和Text共享同一个导航栈条目,调用dismiss()会直接将这个条目从导航栈中移除,自然回到了Home界面(SO1_GAUsername)。
修正方案
如果想实现「点击按钮后关闭ShowAccounts/SelectEntry,保留Text页面」的效果,需要将SelectEntry设为独立的导航栈条目,以下是两种可行方式:
方式1:用NavigationLink跳转SelectEntry
修改LinkEntry的代码:
struct LinkEntry: View { let SRC = "LinkEntry" @Binding var linkedUuid: String? @Environment(\.presentationMode) @Binding private var presentationMode @State private var showTextPage = false var body: some View { let _ = print("\(SRC): Called") Button("Click to select entry") { showTextPage = true } .foregroundColor(.blue) .navigationDestination(isPresented: $showTextPage) { VStack { Text("NavDest: Text-1") // 通过NavigationLink生成新的导航栈条目 NavigationLink("Go to Select Entry") { SelectEntry(linkedUuid: $linkedUuid) } } } } }
此时Text页面是第一个导航条目,SelectEntry是第二个导航条目,调用dismiss()会关闭SelectEntry条目,回到Text页面。
方式2:嵌套navigationDestination
修改LinkEntry和SelectEntry的代码:
struct LinkEntry: View { let SRC = "LinkEntry" @Binding var linkedUuid: String? @Environment(\.presentationMode) @Binding private var presentationMode @State private var showTextPage = false @State private var showSelectEntry = false var body: some View { let _ = print("\(SRC): Called") Button("Click to select entry") { showTextPage = true } .foregroundColor(.blue) .navigationDestination(isPresented: $showTextPage) { Text("NavDest: Text-1") // 在Text页面嵌套导航目标,跳转SelectEntry .navigationDestination(isPresented: $showSelectEntry) { SelectEntry(linkedUuid: $linkedUuid) } .onAppear { showSelectEntry = true } } } } struct SelectEntry: View { let SRC = "SelectEntry" @Binding var linkedUuid: String? @Environment(\.presentationMode) @Binding private var presentationMode var body: some View { let _ = print("\(SRC): Called") ShowAccounts(linkedUuid: $linkedUuid) } }
这种方式下,Text页面是第一个导航条目,SelectEntry是第二个导航条目,调用dismiss()会关闭SelectEntry,回到Text页面。
内容的提问来源于stack exchange,提问作者litbe
相关产品推荐
相关产品推荐

