SwiftUI在TabView中使用NavigationLink跳转失败的问题
SwiftUI在TabView中使用NavigationLink跳转失败的问题

SwiftUI在TabView中使用NavigationLink跳转失败的问题

问题复习

一个朋友在微信交流群里分享一个问题,它的应用在退回首页后,页面的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/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注