在保持TabBar的同时在AppDelagate中打开ViewController

在我的Xcode项目中,当用户点击通知时,我想先将它们发送到tabBar中的某个项目,然后我想实例化一个视图控制器并将对象发送到该视图控制器。 我有代码将它们发送到我想要的tabBar,但我不知道如何将它们实例化到视图控制器,同时保持TabBar和导航栏连接到视图控制器。 所有的答案都需要你改变根视图控制器,这使得当视图控制器被调用时,我失去了与我的tabBar和导航栏的连接。

一个真实生活的例子:用户收到Instagram通知说:“约翰开始关注你” – >用户点击通知 – > Instagram打开并显示通知选项卡 – >快速发送用户到“约翰”configuration文件,当用户按下后退button,它将它们发送回通知选项卡

应该知道:为什么我要去某个选项卡首先是得到该选项卡的导航控制器,因为我要去的视图控制器没有。

这里是我的工作代码发送用户到“通知”选项卡(我添加了评论像Instagram示例更好的理解):

if let tabbarController = self.window!.rootViewController as? UITabBarController { tabbarController.selectedViewController = tabbarController.viewControllers?[3] //goes to notifications tab if type == "follow" { //someone started following current user //send to user's profile and send the user's id so the app can find all the information of the user } } 

首先,你将需要一个TabBarController:

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

然后怀疑TabBarController的所有viewControllers 。 如果你的viewControllersembedded到UINavigationController ? 如果是这样的话,那么你可以试试一下导航控制器:

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

你也应该实例化你想要的ViewController:

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

使所有的NavigationControllers作为TabBarController的viewControllers

 tabBarController.viewControllers = [first, second, third] 

并检查:这是关于你的select。

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

使rootViewController作为rootViewController

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

最后:这是你完成的代码:

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

如果您想在点击通知时显示或推送ViewController? 尝试类似的东西:

 extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { switch response.actionIdentifier { case UNNotificationDefaultActionIdentifier: openViewController() completionHandler() default: break; } } } 

在我上一个实时项目中,我使用了和你一样的方法。 所以即使我怀疑这个方法是处理AppDelegate推送通知的正确还是理想的(我还有很多东西需要在iOS中学习),我还是分享它,因为它对我很有用,我相信代码仍然可读,相当干净。

关键是要知道你的屏幕的水平或堆栈。 什么是childViewControllers,topMost屏幕,在底部的一个,等等…

然后,如果您现在准备推送到某个屏幕,则当然需要当前屏幕的导航控制器。

例如,这个代码块来自我的项目的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 { ... ... 

所以,正如你所看到的,我知道屏幕的层次结构,通过使用这些知识以及通过使用断点printobject (po)来检查我是否在正确的屏幕上的耐心,我得到了正确的参考。 最后,在上面的代码中,我有topMostScreen引用,如果需要,我可以使用该屏幕的navigationController推到新的屏幕。

希望这可以帮助!

我可以想到两种方法来做到这一点:

1)如果该视图控制器是一个UINavigationController,你可以简单地从任何地方推送configuration文件:

 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)另外,我喜欢做的是直接从我的视图控制器子类(在这种情况下,PostListViewController)控制这样的事情。 我在我所有的项目中都包含了一个swift文件中的帮助器方法:

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

然后我会这样做推新视图控制器:

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