Skip to content

Instantly share code, notes, and snippets.

@Kanishka3
Last active December 13, 2021 11:17
Show Gist options
  • Save Kanishka3/edcfd6d5b691f34b1756c7b82b24369a to your computer and use it in GitHub Desktop.
Save Kanishka3/edcfd6d5b691f34b1756c7b82b24369a to your computer and use it in GitHub Desktop.
// NavigationControllerSwiftUI.swift
// Created by Kanishka on 17/11/21.
// More: https://bio.link/kanishka
import SwiftUI
import UIKit
// Reference: https://stackoverflow.com/a/67495147/7992741
struct NavigationController {
/// Pops the current view to the root view
static func popToRootView() {
findNavigationController(viewController: UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController)?
.popToRootViewController(animated: true)
}
/// Pushes a view controller on top of the current view
static func pushController(_ controller: UIViewController){
findNavigationController(viewController: UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController)!.pushViewController(controller, animated: true)
}
/// Allows a function to do actions with the current navigation controller
static func navigationAction(_ action: ((UINavigationController)->())) {
action(findNavigationController(viewController: UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController)!)
}
/// Goes through the application window to find the navigation controller
static private func findNavigationController(viewController: UIViewController?) -> UINavigationController? {
guard let viewController = viewController else {
return nil
}
if let navigationController = viewController as? UINavigationController {
return navigationController
}
for childViewController in viewController.children {
return findNavigationController(viewController: childViewController)
}
return nil
}
}
extension UIApplication {
var keyWindow: UIWindow? {
return UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.first(where: { $0 is UIWindowScene })
.flatMap({ $0 as? UIWindowScene })?.windows
.first(where: \.isKeyWindow)
}
}
@rudrankriyam
Copy link

Do you have an example of this?

@Kanishka3
Copy link
Author

Yep! If you wanna pop to root view or trigger pushController without clicking a button (maybe you are performing a .task {} ) , this is a better option.

PS: I used this for pushing controller in SwiftUI views when shareplay activity was recognized.

@Kanishka3
Copy link
Author

struct FirstView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: SecondView()){
                Text("Go to another view")
            }
        }
    }
}

struct SecondView : View {
    var body: some View {
        Button("Go to root view") {
                        // popping to root without EnvironmentObject
            NavigationController.navigationAction { navigationController in
                navigationController.popToRootViewController(animated: true)
            }
        }.onAppear {
        // triggering a push or pop to root based on a timer or urlsession completion or async task
            Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { _ in
                NavigationController.navigationAction { controller in
                    var view = Color.red
                    var viewController = UIHostingController(rootView: view)
                    controller.pushViewController(viewController, animated: true)
                }
            }
        }
        
    }
}

@rudrankriyam
Copy link

Thanks! Do you think we can use this without NavigationView? and have a UINavigationController as the main controller that handles the FirstView?

@Kanishka3
Copy link
Author

Yep, it works with that too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment