SwiftUI:更改视图并删除父项

SwiftUI: Change view and remove parent

我有一个 NavigationLink 的视图。这个 NavigationLink 是一个 'logout' 按钮,所以当用户点击这个时,我不希望他们能够点击 NavigationBar 中的 "Back" 按钮。有没有办法以编程方式更改视图,并删除“父”视图。

这是带有注销按钮的视图:

struct SettingsView: View {

    @State private var didLogout: Bool = false
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: Login(), isActive: $didLogout) {
                    Button(action: {
                        //logout code here
                        self.didLogout = true
                    }) {
                        Text("Logout")
                    }
                }
            }
        }
    }
}

这是登录视图(用户注销时我推送到的视图):

struct Login: View {
    
    //Login states
    @State var isActive = false
    @State var attemptingLogin = false
    @State var didLoginFail = false
    
    var body: some View {
        
        NavigationView {
            VStack {
                if (attemptingLogin == true) {
                    ProgressView()
                        .progressViewStyle(CircularProgressViewStyle())
                }
                
                NavigationLink(destination: blah(), isActive: $isActive) {
                    Button(action: {
                        attemptingLogin = true
                        blah.Login() { didLogin in
                            if didLogin == true {
                                self.isActive = true
                            } else {
                                self.isActive = false
                                self.didLoginFail = true
                                self.attemptingLogin = false
                            }
                        }
                    }) {
                        Text("Login")
                    }
                }        
            }.padding()
        }
    }
}

我删除了一些该问题不需要的代码。任何帮助将不胜感激,因为我在网上找不到有关此问题的任何信息。我觉得我只是没有正确地表达我的查询,因为我确信很多人在使用 SwiftUI 之前已经 运行 解决过这个问题。

就像我说的,是否有办法“忘记”NavigationView 的历史,并将其视为堆栈中的顶层视图?

SO 上有各种关于“pop to top”或“pop to root”的问题和答案,可能是您要查找的内容:

  • SwiftUI - Is there a popViewController equivalent in SwiftUI?

但是,另一种常见模式是根据您是否登录有条件地显示您的 NavigationView。这可能看起来像这样:

class StateManager : ObservableObject {
    @Published private(set) var isLoggedIn = false
    
    func changeLogin(state: Bool) {
        withAnimation {
            isLoggedIn = state
        }
    }
}

struct ContentView: View {
    @StateObject var stateManager = StateManager()
    
    var body: some View {
        if stateManager.isLoggedIn {
            LoggedInView(stateManager: stateManager)
                .transition(.slide)
        } else {
            LoginView(stateManager: stateManager)
                .transition(.slide)
        }
    }
}

struct LoginView : View {
    @ObservedObject var stateManager : StateManager
    
    var body: some View {
        Button("Log in") {
            stateManager.changeLogin(state: true)
        }
    }
}

struct LoggedInView : View {
    @ObservedObject var stateManager : StateManager
    
    var body: some View {
        NavigationView {
            Button("Log out") {
                stateManager.changeLogin(state: false)
            }.navigationBarTitle("Logged in")
        }
    }
}

到目前为止我所看到的,这不是一个好的做法,通常一个好的逻辑情节提要设计从启动画面开始,然后当您进入您推送到任一选项卡栏的应用程序时被登录或注册屏幕取代或侧边栏屏幕,这是您的主菜单或根菜单,它们的每个项目都嵌入在 navigationView 中以推送到内部视图并从中弹出以返回。如果你不隐藏和显示navigationView会更好。