【问题标题】:Opening ViewController In AppDelegate While Keeping Tabbar在 AppDelegate 中打开 ViewController,同时保持 Tabbar
【发布时间】:2018-04-18 04:16:36
【问题描述】:

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

现实生活中的例子:用户收到 Instagram 通知说“John 开始关注你”-> 用户点击通知 -> Instagram 打开并显示通知选项卡 -> 快速将用户发送到“John " 配置文件,当用户按下后退按钮时,它会将它们发送回通知选项卡

应该知道:我先去某个标签页的原因是为了得到那个标签页的导航控制器,因为我要去的视图控制器没有。

这是我将用户发送到“通知”选项卡的工作代码(为了更好地理解,我添加了 cmets 以类似于 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                    
    }
}

【问题讨论】:

    标签: ios swift xcode uiviewcontroller appdelegate


    【解决方案1】:

    首先,你要满足一个 TabBarController:

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

    然后将 TabBarController 的所有viewControllers 都贪得无厌。如果您的 viewControllers 嵌入到 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
    

    将所有 NavigationController 设为 TabBarController 的viewControllers

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

    将tabBarController设为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;
            }
        }
    }
    

    【讨论】:

    • 神圣的通心粉!对我来说,这似乎是一项巨大的工作。我会试一试,但感觉这应该更简单。
    【解决方案2】:

    我可以想到两种方法:

    1) 如果该视图控制器是 UINavigationController,您可以简单地从任何位置推送配置文件:

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

    【讨论】:

      【解决方案3】:

      在我上一个现场项目中,我使用的方法与您的方法相同。因此,即使我怀疑这种方法对于处理来自 AppDelegate 的推送通知是否正确或理想(我仍然在 iOS 中有很多东西要学习?),我仍然在分享它,因为它对我有用,而且我相信代码仍然可读且相当干净。

      关键是要了解屏幕的级别或堆栈。什么是 childViewControllers、topMost 屏幕、底部的那个等等...

      那么,如果您现在准备好推送到某个屏幕,那么您当然需要您所在当前屏幕的 navigationController。

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

      如您所见,我知道屏幕的层次结构,并且通过使用这些知识以及使用 breakpoints 和 @987654322 检查我是否在正确的屏幕中的耐心@,我得到了正确的参考。最后,在上面的代码中,我有 topMostScreen 引用,如果需要,我可以使用该屏幕的 navigationController 推送到新屏幕。

      希望这会有所帮助!

      【讨论】:

      • 我应该在哪里输入我想去的视图控制器。我首先转到某个选项卡的原因是我可以获取该选项卡的导航控制器,因为我要访问的视图控制器没有
      • 我知道你知道如何以编程方式推送 viewController,对吗?在这种情况下,如果您想推送某个视图控制器(我注意到 Facebook Messenger 会执行此操作,而不管当前选项卡如何),只需创建该视图控制器的新实例然后推送它。明白了吗?
      猜你喜欢
      • 1970-01-01
      • 2013-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-04
      • 1970-01-01
      • 2013-12-30
      相关资源
      最近更新 更多