在保留Tabbar的同时在AppDelegate中打开ViewController

时间:2017-11-06 03:57:27

标签: ios swift xcode uiviewcontroller appdelegate

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

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

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

这是我将用户发送到"通知"的工作代码。 tab(我添加了评论,以便更好地理解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                    
    }
}

3 个答案:

答案 0 :(得分:6)

首先,你要发布一个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

将所有NavigationControllers设为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;
        }
    }
}

答案 1 :(得分:1)

我可以想到两种方法:

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

答案 2 :(得分:1)

在我的上一个直播项目中,我使用与您相同的方法。所以即使我怀疑这种方法对于处理来自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 {

...
...

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

希望这有帮助!