将选项卡栏控制器嵌入导航控制器时的 prepareForSegue

Posted

技术标签:

【中文标题】将选项卡栏控制器嵌入导航控制器时的 prepareForSegue【英文标题】:prepareForSegue when embedding Tab Bar Controller into Navigation Controller 【发布时间】:2016-07-05 11:31:24 【问题描述】:

我目前有这样的导航控制器设置:

还有我的 prepareForSegue,在初始视图(登录视图控制器)和导航控制器之间传递数据如下所示:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
        super.prepareForSegue(segue, sender: sender)
        let navVc = segue.destinationViewController as! UINavigationController // 1
        let chatVc = navVc.viewControllers.first as! ChatViewController // 2
        chatVc.senderId = userID // 3
        chatVc.senderDisplayName = "" // 4
    

但是,当我尝试像这样嵌入标签栏控制器(为我的应用添加更多页面/功能)时..​​.

...运行我的应用程序,我的程序在let navVc = segue.destinationViewController as! UINavigationController 行崩溃

我知道问题在于,在我的初始视图之后,它会转到类型为 UITabBarController 而不是 UINavigationController 的标签栏,但是如果我更改它,我的数据不会转到我想要的视图去...这有点令人困惑。

如果您对如何实现此功能有任何想法,请告诉我,或者如果您有任何问题,请随时向我询问。

谢谢!

附:我在控制台中收到的错误是:

Could not cast value of type 'UITabBarController' (0x10b8e48b0) to 'UINavigationController' (0x10b8e4860).

【问题讨论】:

【参考方案1】:

试试这个:

首先将destinationViewController 转换为UITabBarController,然后使用viewControllers 属性访问tabBarController 中的第一个viewController:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

    let tabVc = segue.destinationViewController as! UITabBarController
    let navVc = tabVc.viewControllers!.first as! UINavigationController
    let chatVc = navVc.viewControllers.first as! ChatViewController
    chatVc.senderId = userID
    chatVc.senderDisplayName = ""

【讨论】:

谢谢!它起作用了,但是我的观点被切断了。有没有办法以编程方式调整我的视图以相对于标签栏进行缩放? 你的 viewController 布局是否带有自适应约束? 我正在处理这个没有传递数据的问题,我已经用你的回答解决了我的问题。谢谢! @MarioBurga,我很高兴它有帮助!【参考方案2】:

在 CS193p 课程中,Paul Hegarty 展示了使用 extensions 来处理导航控制器 segues(第 8 讲:23')。 UIViewController 扩展引入了一个新的计算属性:contentViewController 可用于所有 UIViewController(和子类)。

我在下面发布的代码也适用于 TabBarViewControllers。

当您尝试将导航控制器转换为 ChatViewController 时,segue.destinationController.contentViewController 将递归返回 ChatViewController。

class LoginViewController: UIViewController 

    /* ... */

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
        if let chatVc = segue.destinationViewController.contentViewController as? ChatViewController 
            chatVc.senderId = userID
            chatVc.senderDisplayName = ""
        
    



extension UIViewController 

    var contentViewController: UIViewController 
        if let navcon = self as? UINavigationController 
            return navcon.visibleViewController ?? self
         else if let tabcon = self as? UITabBarController 
            return tabcon.selectedViewController ?? self
         else 
            return self
        
    


【讨论】:

【参考方案3】:

一种简洁的方法是在您登录后立即使用以下内容:

let controller = self.storyboard?.instantiateViewControllerWithIdentifier("setthisisyourstoryboard") as! UITabBarController  // This would instantiate the TabBarController.

let navInstance = controller[0] as! UINavigationController // This would instantiate the navigationController, that is placed at 0th index in the array of all view controllers that are child to TabBarController, since you only have one child, you can use 0 as index


if navInstance.viewControllers[0] is YourClassName   // YouClassName is the name of the class right next to the navigation view controller, and it is also the only child of navigation Controller(0 index)
// You can also send some data here (for example the sender id)
 (navInstance.viewControllers[0] as! YourClassName).someProperty = Value
                        

 // This line would present the tabBar controller, that would ultimately reach the end of the stack. I have used this approach in many apps, it works great!

self.presentViewController(controller, animated: true, completion: nil)

您可以在此之后删除segue并为tabbarcontroller设置storyboard id。

我喜欢这样做,因为它更自然。我的意思是 UITabBarController 主要是 View Controller 的父级,我不喜欢将 UITabBarController 设置为 UIView Controller 的子级的想法。

也许这并没有什么问题,但我不喜欢它。

【讨论】:

【参考方案4】:

这里。它对我来说很好用:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if let tabVC = segue.destination as? UITabBarController 
        if let navVC = tabVC.viewControllers!.first as? UINavigationController 
            if let nextVC =  navVC.viewControllers.first as? NextVC 
                nextVC.varName = "works like a charm"
            
        
    

NextVC 是您要将变量发送到的目标 VC。

【讨论】:

以上是关于将选项卡栏控制器嵌入导航控制器时的 prepareForSegue的主要内容,如果未能解决你的问题,请参考以下文章

如何使用情节提要正确地转到嵌入式选项卡栏和导航控制器?

在启动时以编程方式为 5 个选项卡栏项目设置选项卡栏标题,其中 4 个嵌入在导航控制器中,1 个没有。目标 C

Xcode 4.2 在 IB 的选项卡栏上放置导航控制器时的警告

如何快速隐藏嵌入在导航堆栈中的视图控制器中的选项卡栏?

我已将 ViewController 嵌入选项卡栏控制器中,现在我的 coreDataStack.managedContext 失败

在标签栏控制器中嵌入导航控制器会更改视图控制器的安全区域