Push View programmatically in callback, SwiftUI Push View programmatically in callback, SwiftUI swift swift

Push View programmatically in callback, SwiftUI


I've found the answer. If you want to show another view on callback you should

  1. Create state @State var pushActive = false

  2. When ViewModel notifies that login is successful set pushActive to true

    func handleSuccessfullLogin() {    self.pushActive = true    print("handleSuccessfullLogin")}
  3. Create hidden NavigationLink and bind to that state

    NavigationLink(destination:    ProfileView(viewModel: ProfileViewModelImpl()),   isActive: self.$pushActive) {     EmptyView()}.hidden()


I'm adding some snippets here because I think it simplifies some things and makes reusing navigation links easier:

1. Add View Navigation Extensions

extension View {    func navigatePush(whenTrue toggle: Binding<Bool>) -> some View {        NavigationLink(            destination: self,            isActive: toggle        ) { EmptyView() }    }    func navigatePush<H: Hashable>(when binding: Binding<H>,                                   matches: H) -> some View {        NavigationLink(            destination: self,            tag: matches,            selection: Binding<H?>(binding)        ) { EmptyView() }    }    func navigatePush<H: Hashable>(when binding: Binding<H?>,                                   matches: H) -> some View {        NavigationLink(            destination: self,            tag: matches,            selection: binding        ) { EmptyView() }    }}

Now, you can call on any view (make sure they (or a parent) are in a navigation view)

2. Use at leisure

struct Example: View {    @State var toggle = false    @State var tag = 0    var body: some View {        NavigationView {            VStack(alignment: .center, spacing: 24) {                Text("toggle pushed me")                    .navigatePush(whenTrue: $toggle)                Text("tag pushed me (2)")                    .navigatePush(when: $tag, matches: 2)                Text("tag pushed me (4)")                    .navigatePush(when: $tag, matches: 4)                Button("toggle") {                    self.toggle = true                }                Button("set tag 2") {                    self.tag = 2                }                Button("set tag 4") {                    self.tag = 4                }            }        }    }}


as @Bhodan mentioned you can do it by changing state

Using EnvironmentObject with SwiftUI

  1. Add UserData ObservableObject :
class UserData: ObservableObject, Identifiable {    let id = UUID()    @Published var firebase_uid: String = ""    @Published var name: String = ""    @Published var email: String = ""    @Published var loggedIn: Bool = false}

the loggedIn property will be used to monitor when a change in user logs in or out

  1. Now add it as an @EnvironmentObject in your SceneDelegate.swift file in Xcodethis just makes it so its accessible everywhere in your app
class SceneDelegate: UIResponder, UIWindowSceneDelegate {    var window: UIWindow?    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).        // Create the SwiftUI view that provides the window contents.        let userData = UserData()        let contentView = ContentView().environmentObject(userData)        // Use a UIHostingController as window root view controller.        if let windowScene = scene as? UIWindowScene {            let window = UIWindow(windowScene: windowScene)            window.rootViewController = UIHostingController(rootView: contentView)            self.window = window            window.makeKeyAndVisible()        }    }

Once you make any change to the loggedIn property any UI that is Binded to it will respond to the true/false value change

the as @Bhodan mentioned just add this to your view and it will respond to that change

struct LoginView: View {@EnvironmentObject var userData: UserDatavar body: some View {NavigationView {VStack {NavigationLink(destination: ProfileView(), isActive: self.$userData.loggedin) {    EmptyView()    }.hidden()   }  } }}