Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically navigate to new view in SwiftUI

Tags:

swift

swiftui

Descriptive example:

login screen, user taps "Login" button, request is performed, UI shows waiting indicator, then after successful response I'd like to automatically navigate user to the next screen.

How can I achieve such automatic transition in SwiftUI?

like image 923
zgorawski Avatar asked Jun 25 '19 12:06

zgorawski


People also ask

How do I push a new view in SwiftUI?

Allowing to push a new screen onto a navigation stack is as simple as wrapping your SwiftUI views into a NavigationLink wrapper. As long as you contain your views in a navigation view, you'll be able to push new destination views.

How do I add a SwiftUI view to Uiviewcontroller?

Open the Library by clicking on the + button in Xcode's top right corner. Search for UIHostingController and drag and drop it to the Storyboard. To create a Segue control-drag (hold down the ctrl key and drag the element) from the UIButton in the main ViewController to the UIHostingController we have just added.


2 Answers

You can replace the next view with your login view after a successful login. For example:

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()
        }

    }
}

You should handle your login process in your data model and use bindings such as @EnvironmentObject to pass isLoggedin to your view.

Note: In Xcode Version 11.0 beta 4, to conform to protocol 'BindableObject' the willChange property has to be added

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)
    // }
  }
}
like image 198
M Reza Avatar answered Oct 19 '22 19:10

M Reza


For future reference, as a number of users have reported getting the error "Function declares an opaque return type", to implement the above code from @MoRezaFarahani requires the following syntax:

struct ContentView: View {

    @EnvironmentObject var userAuth: UserAuth 

    var body: some View {
        if !userAuth.isLoggedin {
            return AnyView(LoginView())
        } else {
            return AnyView(NextView())
        }

    }
}

This is working with Xcode 11.4 and Swift 5

like image 6
Ryan Avatar answered Oct 19 '22 18:10

Ryan