Opening ViewController In AppDelegate While Keeping Tabbar

喜你入骨 提交于 2019-11-28 01:38:20

First of all, you'll to insatiate a TabBarController:

let storyboard = UIStoryboard.init(name: "YourStoryboardName", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "YourTabBarController") as! UITabBarController

And then insatiate all of the viewControllers of TabBarController. If your viewControllers is embedded in to the UINavigationController? If so, you'll to insatiate a Navigation Controller instead:

let first = storyboard.instantiateViewiController(withIdentifier: "YourFirstNavigationController") as! UINavigationController
let second = storyboard.instantiateViewiController(withIdentifier: "YourSecondNavigationController") as! UINavigationController
let third = storyboard.instantiateViewiController(withIdentifier: "YourThirdNavigationController") as! UINavigationController

Also you should instantiate your desired ViewController too:

let desiredVC = storyboard.instantiateViewController(withIdentifier: "desiredVC") as! ExampleDesiredViewController

Make all of the NavigationControllers as viewControllers of TabBarController:

tabBarController.viewControllers = [first, second, third]

And check: It's about your choice.

if tabBarController.selectedViewController == first {

// Option 1: If you want to present
first.present(desiredVC, animated: true, completion: nil)

// Option 2: If you want to push
first.pushViewController(desiredVC, animated. true)

}

Make tabBarController as a rootViewController:

self.window = UIWindow.init(frame: UIScreen.main.bounds)   
self.window?.rootViewController = tabBarController
self.window?.makeKeyAndVisible()

Finally: It's your completed code:

func openViewController() {

let storyboard = UIStoryboard.init(name: "YourStoryboardName", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "YourTabBarController") as! UITabBarController

let first = storyboard.instantiateViewiController(withIdentifier: "YourFirstNavigationController") as! UINavigationController
let second = storyboard.instantiateViewiController(withIdentifier: "YourSecondNavigationController") as! UINavigationController
let third = storyboard.instantiateViewiController(withIdentifier: "YourThirdNavigationController") as! UINavigationController

let desiredVC = storyboard.instantiateViewController(withIdentifier: "desiredVC") as! ExampleDesiredViewController

tabBarController.viewControllers = [first, second, third]

if tabBarController.selectedViewController == first {

// Option 1: If you want to present
first.present(desiredVC, animated: true, completion: nil)

// Option 2: If you want to push
first.pushViewController(desiredVC, animated. true)

}

self.window = UIWindow.init(frame: UIScreen.main.bounds)   
self.window?.rootViewController = tabBarController
self.window?.makeKeyAndVisible()

}

If you want to present or push ViewController when the notification is tapped? Try something like that:

extension AppDelegate: UNUserNotificationCenterDelegate {

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

        switch response.actionIdentifier {
        case UNNotificationDefaultActionIdentifier:
            openViewController()
            completionHandler()

        default:
            break;
        }
    }
}

In my last live project, I'm using the same approach like yours. So even though I doubt this method is the correct or ideal for handling a push notification from the AppDelegate (I still got a lot of stuff to learn in iOS 🙂), I'm still sharing it because it worked for me and well I believe the code is still readable and quite clean.

The key is to know the levels or stacks of your screens. The what are childViewControllers, the topMost screen, the one the is in the bottom, etc...

Then if you're now ready to push to a certain screen, you would need of course the navigationController of the current screen you're in.

For instance, this code block is from my project's AppDelegate:

    func handleDeeplinkedJobId(_ jobIdInt: Int) {
        // Check if user is in Auth or in Jobs
        if let currentRootViewController = UIApplication.shared.keyWindow!.rootViewController,
            let presentedViewController = currentRootViewController.presentedViewController {
            if presentedViewController is BaseTabBarController {
                if let baseTabBarController = presentedViewController as? BaseTabBarController,
                    let tabIndex = TabIndex(rawValue: baseTabBarController.selectedIndex) {
                    switch tabIndex {
                    case .jobsTab:
....

....

                    if let jobsTabNavCon = baseTabBarController.viewControllers?.first,
                        let firstScreen = jobsTabNavCon.childViewControllers.first,
                        let topMostScreen = jobsTabNavCon.childViewControllers.last {

...
...

So as you can see, I know the hierarchy of the screens, and by using this knowledge as well as some patience in checking if I'm in the right screen by using breakpoints and printobject (po), I get the correct reference. Lastly, in the code above, I have the topMostScreen reference, and I can use that screen's navigationController to push to a new screen if I want to.

Hope this helps!

I can think of two ways to do that:

1) If that view controller is a UINavigationController you can simply push the profile from wherever you are:

if let tabNavigationController = tabbarController.viewControllers?[3] as? UINavigationController {
    tabbarController.selectedViewController = tabNavigationController
    let profileViewController = ProfileViewController(...)
    // ... set up the profile by setting the user id or whatever you need to do ...
    tabNavigationController.push(profileViewController, animated: true)    // animated or not, your choice ;)
}

2) Alternatively, what I like to do is control such things directly from my view controller subclass (in this case, PostListViewController). I have this helper method in a swift file that I include in all of my projects:

extension UIViewController {
    var containedViewController: UIViewController {
        if let navController = self as? UINavigationController, let first = navController.viewControllers.first {
            return first
        }
        return self
    }
}

Then I would do this to push the new view controller:

if let tabViewController = tabbarController.selectedViewController {
    tabbarController.selectedViewController = tabViewController
    if let postListViewController = tabViewController.containedViewController as? PostListViewController {
        postListViewController.goToProfile(for: user)    // you need to get the user reference from somewhere first
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!