代码之家  ›  专栏  ›  技术社区  ›  zgorawski

以编程方式导航到SwiftUI中的新视图

  •  0
  • zgorawski  · 技术社区  · 7 年前

    登录屏幕,用户点击“登录”按钮,执行请求,UI显示等待指示器,然后在成功响应后,我想自动将用户导航到下一个屏幕。

    0 回复  |  直到 6 年前
        1
  •  26
  •   Gene Z. Ragan    6 年前

    成功登录后,可以用登录视图替换下一个视图。例如:

    struct LoginView: View {
        var body: some View {
            ...
        }
    }
    
    struct NextView: View {
        var body: some View {
            ...
        }
    }
    
    // Your starting view
    struct ContentView: View {
    
        @EnvironmentObject var userAuth: UserAuth 
    
        var body: some View {
            if !userAuth.isLoggedin {
                LoginView()
            } else {
                NextView()
            }
    
        }
    }
    

    您应该在数据模型中处理登录过程,并使用绑定,例如 @EnvironmentObject isLoggedin 同意你的观点。

    注: 版本11.0 beta 4 ,以符合协议 “BindableObject” 这个 willChange 必须添加属性

    import Combine
    
    class UserAuth: ObservableObject {
    
      let didChange = PassthroughSubject<UserAuth,Never>()
    
      // required to conform to protocol 'ObservableObject' 
      let willChange = PassthroughSubject<UserAuth,Never>()
    
      func login() {
        // login request... on success:
        self.isLoggedin = true
      }
    
      var isLoggedin = false {
        didSet {
          didChange.send(self)
        }
    
        // willSet {
        //       willChange.send(self)
        // }
      }
    }
    
        2
  •  6
  •   Ryan    6 年前

    struct ContentView: View {
    
        @EnvironmentObject var userAuth: UserAuth 
    
        var body: some View {
            if !userAuth.isLoggedin {
                return AnyView(LoginView())
            } else {
                return AnyView(NextView())
            }
    
        }
    }
    

    这是与Xcode 11.4和Swift 5一起使用的

        3
  •  5
  •   David Rozmajzl    6 年前
    struct LoginView: View {
        
        @State var isActive = false
        @State var attemptingLogin = false
        
        var body: some View {
            ZStack {
                NavigationLink(destination: HomePage(), isActive: $isActive) {
                    Button(action: {
                        attlempinglogin = true
                        // Your login function will most likely have a closure in 
                        // which you change the state of isActive to true in order 
                        // to trigger a transition
                        loginFunction() { response in
                            if response == .success {
                                self.isActive = true
                            } else {
                                self.attemptingLogin = false
                            }
                        }
                    }) {
                        Text("login")
                    }
                }
                
                WaitingIndicator()
                    .opacity(attemptingLogin ? 1.0 : 0.0)
            }
        }
    }
    

    将导航链接与$isActive绑定变量一起使用

        4
  •  4
  •   Nicos Karalis    5 年前

    根据截至的联合收割机上的更改,阐述其他人已阐述的内容 Swift Version 5.2

    1. 创建一个类名 UserAuth 如下所示,不要忘记导入 import Combine
    class UserAuth: ObservableObject {
            @Published var isLoggedin:Bool = false
    
            func login() {
                self.isLoggedin = true
            }
        }
    
    1. 使现代化 SceneDelegate.Swift 具有

      let contentView = ContentView().environmentObject(UserAuth())

    2. 您的身份验证视图

       struct LoginView: View {
          @EnvironmentObject  var  userAuth: UserAuth
          var body: some View {
              ...
          if ... {
          self.userAuth.login()
          } else {
          ...
          }
       }
      }
      
      
    3. 验证成功后,如果验证失败 userAuth.isLoggedin = true 然后它将被加载。

         struct NextView: View {
           var body: some View {
           ...
           }
         }
      
    struct ContentView: View {
        @EnvironmentObject var userAuth: UserAuth 
        var body: some View {
            if !userAuth.isLoggedin {
                    LoginView()
                } else {
                    NextView()
                }
        }
      }
    
        5
  •  1
  •   Zorayr    6 年前

    这是电话的分机 UINavigationController NavigationLink isActive 绑定是正确的方法,但它既不灵活也不可扩展。下面的扩展为我做了一个技巧:

    /**
     * Since SwiftUI doesn't have a scalable programmatic navigation, this could be used as
     * replacement. It just adds push/pop methods that host SwiftUI views in UIHostingController.
     */
    extension UINavigationController: UINavigationControllerDelegate {
    
        convenience init(rootView: AnyView) {
            let hostingView = UIHostingController(rootView: rootView)
            self.init(rootViewController: hostingView)
    
            // Doing this to hide the nav bar since I am expecting SwiftUI
            // views to be wrapped in NavigationViews in case they need nav.
            self.delegate = self
        }
    
        public func pushView(view:AnyView) {
            let hostingView = UIHostingController(rootView: view)
            self.pushViewController(hostingView, animated: true)
        }
    
        public func popView() {
            self.popViewController(animated: true)
        }
    
        public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
            navigationController.navigationBar.isHidden = true
        }
    }
    

    下面是一个简单的例子,使用这个 window.rootViewController

    var appNavigationController = UINavigationController.init(rootView: rootView)
    window.rootViewController = appNavigationController
    window.makeKeyAndVisible()
    
    // Now you can use appNavigationController like any UINavigationController, but with SwiftUI views i.e. 
    appNavigationController.pushView(view: AnyView(MySwiftUILoginView()))
    
        6
  •  1
  •   John Smith    5 年前

    我遵循了Gene的答案,但我在下面解决了两个问题。首先,变量isLoggedIn必须具有属性@Published才能按预期工作。第二个问题是如何实际使用环境对象。

    @Published var isLoggedin = false {
    didSet {
      didChange.send(self)
    }
    

    第二个问题是如何实际使用环境对象。吉恩的回答并不是真的错,我只是注意到评论中有很多关于它的问题,我没有足够的因果报应来回应它们。将此添加到ScenedLegate视图:

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        var userAuth = UserAuth()
        
        // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView().environmentObject(userAuth)
    
        7
  •  0
  •   xxcat    7 年前

    现在,您只需创建要导航到的新视图的实例,并将其放入NavigationButton:

    NavigationButton(destination: NextView(), isDetail: true, onTrigger: { () -> Bool in
        return self.done
    }) {
        Text("Login")
    }
    

    如果返回true,则表示您已成功登录用户。