问题复习
一个朋友在微信交流群里分享一个问题,它的应用在退回首页后,页面的TabView仍然存在。
下面是当时截图的一个结构。

我这边根据代码,分析了一下问题为:应用第一次打开显示的是登陆视图,在登陆视图中点击“登陆”按钮后,会跳转到主视图中。

当用户点击“我的”视图的“退出登陆”按钮后,就变成开始的结构图,视图是返回到登陆视图了,但是底部仍然是TabView的四个切换按钮。
我发现退出登陆是在主界面中“我的”视图里,Button将isLoggedOut变量改为true,然后通过NavigationLink的isActive构造方法跳转回登陆视图。
//退出
Button(action:{
isLoggedOut = true
}){
Text("退出登录")
}
NavigationLink(destination: ContentView(), isActive: $isLoggedOut) {
EmptyView()
}
我根据应用显示的内容发现,实际上就是TabView的第四个“我的”视图变成了登陆视图,其他的视图仍然存在。因此,就出现了最开始登陆视图显示TabView的内容。

因此,当在我的视图中修改isLoggedOut变量并调用NavigationLink时,实际上只有我的视图跳转成了登陆视图,其他的视图保持不变。
问题原因
经过排查了解到NavigationLink(destination:isActive:) 只能控制它所在视图的导航栈。当用户在我的视图中触发跳转时,实际上只影响了我的视图这个Tab的导航栈。
因为SwiftUI的TabView的每个tab是“独立的NavigationView”栈,因此在我的视图中使用NavigationLink(destination:isActive:)时,是这个tab嵌套了一个登陆视图。
在具体一点讲,就是每个Tab的View是独立的视图,不共享导航状态。在我的视图中调用的NavigationLink(destination:isActive:),这个link只作用于我的视图的栈。
因此,不会影响到其他的Tab的视图结构和状态,更不会替换掉这个TabView。
解决方案
解决方案就是设置一个顶层视图来判断登录页还是主视图:
struct RootView: View {
@State private var isLoggedIn = false
var body: some View {
NavigationView {
if isLoggedIn {
BaseTabbarView(isLoggedIn: $isLoggedIn)
} else {
ContentView(isLoggedIn: $isLoggedIn)
}
}
}
}
然后在主视图中这样处理登录按钮:
struct ContentView: View {
@Binding var isLoggedIn: Bool
// 其他状态...
var body: some View {
// 登录页面UI
Button("立即登录") {
isLoggedIn = true // 登录成功,跳转到主页
}
}
}
在TabView视图中,传入这个绑定,当需要时设置为false并从我的视图中退出登陆。
struct BaseTabbarView: View {
@Binding var isLoggedIn: Bool
@State private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
// 其他 Tab
MineView(isLoggedIn: $isLoggedIn)
.tabItem {
Label("我的", systemImage: "person")
}
.tag(3)
}
}
}
TabView中的我的视图代码:
struct MineView: View {
@Binding var isLoggedIn: Bool
var body: some View {
VStack {
Text("用户信息")
Button("退出登录") {
isLoggedIn = false // 返回登录页
}
}
}
}
总结
这个问题实际上就是NavigationLink只改变了TabView中一个视图的栈,而没有修改整个TabView视图导致的问题。
一般来讲,应用的TabView也只是会在主视图中,如果想要退回到登陆视图或其他的应用,应该使用@Binding来传递参数。另外,NavigationLink更像是视图的栈,而不是退回到其他的栈。

这是一个互相嵌套的视图(与前面的案例无关),在登陆视图中调用NavigationLink会跳转到主视图,在主视图中调用NavigationLink会跳转到我的视图,从我的视图中调用NavigationLink跳转到登陆视图。
因此,本质上还是一层一层的嵌套,最外层还是登陆视图,只是在登陆视图中通过NavigationLink显示了其他的视图。但返回时,实际上也是逐层回退。

相关文章
1、SwiftUI导航视图控件NavigationLink:https://fangjunyu.com/2024/12/11/swiftui%e5%af%bc%e8%88%aa%e8%a7%86%e5%9b%be%e6%8e%a7%e4%bb%b6navigationlink/
2、SwiftUI选项卡式视图切换TabView:https://fangjunyu.com/2024/12/09/swiftui%e9%80%89%e9%a1%b9%e5%8d%a1%e5%bc%8f%e8%a7%86%e5%9b%be%e5%88%87%e6%8d%a2tabview/