通过 NavigationController-TabBarController-NavigationController 以编程方式导航

Posted

技术标签:

【中文标题】通过 NavigationController-TabBarController-NavigationController 以编程方式导航【英文标题】:Navigate programmatically through NavigationController-TabBarController-NavigationController 【发布时间】:2018-01-14 23:05:03 【问题描述】:

我的基于 Storyboard 的应用具有以下结构:

NavigationController (NavCa) —> CollectionViewController (VCa) —> 模态呈现 —> TabBarController (TabBarC)

TabBarC 有两个选项卡,每个选项卡都嵌入在自己的 NavigationController 中:

TabBar[0] NavigationController (NavCTab0) —> TableViewController (VC01) —> ViewController (VC02) —> ViewController (VC03)

TabBar[1] NavigationController (NavCTab1) —> ViewController (VC11) —> ViewController (VC12)

我的问题:我的一个 3D QuickAction 必须直接导航到 VC01。

我确实检查了该网站。主题Swift: Programmatically transitioning from 1 view to another via a TabBar and Navigation Controller 看起来非常接近我的。我尝试了代码(AppDelegate.swift 中的快速操作处理程序):

let mainSB = UIStoryboard(name: "Main", bundle: nil)
let tbc = mainSB.instantiateViewController(withIdentifier: “TabBarC”) as? TabBarController
tbc?.selectedIndex = 0
let ncTab0  = tbc?.viewControllers![0] as! UINavigationController

let vc01 = mainSB.instantiateViewController(withIdentifier: “VC01”) as! TableViewController01
let vc02 = mainSB.instantiateViewController(withIdentifier: “VC02”) as! ViewController02
let vc03 = mainSB.instantiateViewController(withIdentifier: “VC03”) as! ViewController03
let arrayOfVC = [vc01, vc02, vc03]
ncTab0.setViewControllers(arrayOfVC, animated: false)

ncTab0.popToViewController(vc01, animated: true)
self.window?.rootViewController?.present(tbc, animated: true, completion: nil)

但什么也没发生。输出窗口中没有任何内容。应用中什么也没有发生(如果应用被终止,它会启动 VCa 屏幕;如果应用没有被终止,它会停留在快速操作之前的位置)。

非常感谢任何帮助。

附:我只会说 SWIFT。

编辑

我的 AppDelegate.swift 和 Quick Action Handler:

class AppDelegate: UIResponder, UIApplicationDelegate 

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 

        var isLaunchedFromQuickAction = false

        // Check if it's launched from Quick Action
        if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem 

            isLaunchedFromQuickAction = true
            _ = handleQuickAction(shortcutItem)
        

        // Return false if the app was launched from a shortcut, so performAction... will not be called.
        return !isLaunchedFromQuickAction
    

    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) 
        completionHandler(handleQuickAction(shortcutItem))
    

    func handleQuickAction(_ shortcutItem: UIApplicationShortcutItem) -> Bool 

        var quickActionHandled = false
        let type = shortcutItem.type.components(separatedBy: ".").last!
        if type == "QuickAction1" 
            ... // Navigating to VC01, see piece of code above
            quickActionHandled = true
        
    
    return quickActionHandled

我在其他应用中使用的相同快速操作处理程序。该应用程序的结构为 NavigationController --> ViewController1 --> ViewController2 --> ViewController3。还有一个快速操作导航到 ViewController2。它就像一个魅力。 与新应用程序的唯一区别是应用程序结构。我无法通过所有这些 TabBarControllers、NavigationControllers 等赢得导航......

编辑 2

按照建议,我尝试了 Apple 示例代码 (https://developer.apple.com/library/content/samplecode/ApplicationShortcuts/Introduction/Intro.html#//apple_ref/doc/uid/TP40016545-Intro-DontLinkElementID_2) 中的另一种快速操作处理方法。而且......它现在可以工作了。部分。

如果我终止应用程序,3D 快速操作将完美运行。

但是。如果我不终止应用程序并且仅在后台发送它 - 快速操作不起作用并且在控制台中我收到相同的旧消息:'警告:尝试在 上呈现 其视图不在窗口层次结构中!'。

有什么想法吗?

编辑 3

最终解决方案。

完全按照 Apple 示例代码 (https://developer.apple.com/library/content/samplecode/ApplicationShortcuts/Introduction/Intro.html#//apple_ref/doc/uid/TP40016545-Intro-DontLinkElementID_2) 中的 3D 快速操作在 AppDelegate.swift 中的开关 shortCutType 下进行快速操作并导航到“VC01”

case ShortcutIdentifier.first.type:
    // Handle shortcut 1 (static).
    let mainSB = UIStoryboard(name: "Main", bundle: nil)
    let tbc = mainSB.instantiateViewController(withIdentifier: "TabBarC") as? TabBarController
    self.window?.rootViewController?.dismiss(animated: true, completion: nil)
    self.window?.rootViewController?.present(tbc!, animated: true, completion: nil)
    handled = true
    break

此代码经过测试并且有效。

【问题讨论】:

如果你有一个普通的基于 StoryBoard 的应用程序,你不需要实例化你自己的视图控制器。 @ryantxr 请继续。我很高兴看到您的解决方案。 您是否已通过调试器验证此代码是否正在运行?查看更多 AppDelegate 可能会有所帮助。您是否将 AppDelegate 代码与 ApplicationShortcuts 示例 Swift 应用程序进行了比较? 你的导航控制器有 segues 吗? @ozzieozumo 代码正在运行。我的其他 3D 快速操作没有问题。我会说这是一个“标准”的 3D 快速动作实现。问题是导航... 【参考方案1】:

根据我对你的代码的理解,我认为只需要三行代码就足够了

let mainSB = UIStoryboard(name: "Main", bundle: nil)
let tbc = mainSB.instantiateViewController(withIdentifier: “TabBarC”) as? TabBarController
self.window?.rootViewController.present(tbc, animated: true, completion: nil)

由于选项卡栏视图控制器似乎仅在情节提要中设置。默认选中tabbar Controller的第一个tab。

编辑

“尝试呈现……”问题的其他解决方案 您可以设置标志,并在视图控制器的 viewDidLoad 方法中尝试以与代码中相同的方式呈现 tabBarViewController。

【讨论】:

完全同意这种简化。但是,原始代码也应该可以工作。 @Van 我刚刚测试了你的建议。该应用程序忽略它。在控制台中我收到一条警告:“警告:尝试在 上显示 ,其视图不在窗口层次结构中!” 因为您可能是从 appDidfinishlaunchingOptions 调用它,其中根视图尚未在前台。尝试 ro add in applicationDidBecomeActive 但是你需要添加条件,因为即使你从后台回来,这个方法也会一直被调用。 rootViewController 是可选的。你的代码怎么会有 window?.rootViewController.present .. 这应该是一个编译错误,因为你没有解开 rootViewController。这是真正的代码吗?您能否显示更多实际的 AppDelegate 代码,即您在哪里调用此代码等。查看示例快捷方式应用程序如何使用 didBecomeActive。你也是这样吗? 很高兴您取得了进展。当您在后台运行应用程序时哪个视图可见(不工作的场景)?我认为(不是 100% 确定)您的 performActionForShortcut 需要考虑标签栏已经以模态方式呈现的可能性。如果是,您可以简单地关闭它,然后调用您现有的快捷方式处理程序。我认为值得一试。

以上是关于通过 NavigationController-TabBarController-NavigationController 以编程方式导航的主要内容,如果未能解决你的问题,请参考以下文章

下拉框多选框单选框 通过TagHelper绑定数据

酶:测试孩子通过安装渲染失败,但通过浅时通过

java是通过值传递,也就是通过拷贝传递——通过方法操作不同类型的变量加深理解

通过代码进行 Spring 配置与通过注释进行配置

如何理解“不要通过共享内存来通信,而应该通过通信来共享内存”?

通过邮递员通过 API 使用 Rails 主动存储上传文件(.pdf、.jpg 等)? (不通过 Rails 视图)