首页 文章

UINabigationController里面的一个UITabBarController里面的UISplitViewController在iPhone上以模态方式呈现

提问于
浏览
13

我有一个UISplitViewController,它包含一个UITabBarController作为主视图 . 这个UITabBarController包含一个UINavigationController . 详细视图也包含UINavigationController .

Storyboard

在iPad上,这可以按预期工作 . show detail segue在详细视图上显示导航控制器内的imageview .

另一方面,在iPhone上,我预计show detail segue会在主视图的导航控制器的堆栈上推送详细视图 . 但实际上它是在主视图上以模态方式呈现的 .

从故事板中删除UITabBarController并直接在主视图中使用UINavigationController时,这可以正常工作 .

有没有人知道如何在iPhone的主控UINavigationController堆栈上呈现详细视图?

5 回答

  • 9

    @PeterOettl对他自己的问题的回答让我走上了正确的道路并且非常棒 . 所以归功于他 .

    我和他有几乎相同的故事板结构,但由于 vcnavigationController 我收到运行时错误说

    '不支持推送导航控制器'

    如上所述,这是因为 vc 是详细视图的 navigationController 而不是详细视图的viewController .

    请注意,我很惊讶@PeterOettl在他的情况下也没有得到错误,因为故事板图片中给出的segue指向详细视图的导航控制器 .

    因此代码应该像(在Swift中)简单地添加

    let detailViewControllerNavigationController = (vc as UINavigationController).viewControllers[0] as UIViewController
    

    并推 detailViewControllerNavigationController 而不是 vc

    而整个代码是

    func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool {
        println("UISplitViewController collapsed: \(splitViewController.collapsed)")
        if (splitViewController.collapsed) {
            let master = splitViewController.viewControllers[0] as UITabBarController
            let masterNavigationController = master.selectedViewController as UINavigationController
    
            let detailViewControllerNavigationController = (vc as UINavigationController).viewControllers[0] as UIViewController
    
            masterNavigationController.pushViewController(detailViewControllerNavigationController, animated: true)
    
            return true
        } else {
            return false
        }
    }
    

    另请注意,此代码放在Xcode的主 - 详细示例的 AppDelegate.swift 中,其中在主视图中添加了选项卡栏 .

    EDIT

    在评论中我们与@PeterOettl讨论了 .pushViewController.showViewController 之间的区别 .

    Apple文档说:

    showViewController:sender:此方法以与pushViewController:animated:方法类似的方式将新视图控制器推送到导航堆栈 . 如果需要,可以直接调用此方法,但通常在需要显示新视图控制器时从视图控制器层次结构中的其他位置调用此方法 . 适用于iOS 8.0及更高版本 .

  • 0

    The problem with Peter's solution is that it will fall apart with the iPhone 6 +. 怎么样?使用该代码,如果iPhone 6处于纵向 - 细节视图将推送到导航堆栈 . 到目前为止,一切都很好 . 现在,旋转到横向,然后您将详细视图显示为主视图的详细视图 and .

    您需要拆分视图控制器的委托来实现两种方法:

    - (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)detailVC sender:(id)sender
    {
        UITabBarController *masterVC = splitViewController.viewControllers[0];
    
        if (splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact)
            [masterVC.selectedViewController showViewController:detailVC sender:sender];
        else
            [splitViewController setViewControllers:@[masterVC, detailVC]];
    
        return YES;
    }
    

    现在,您需要从选定选项卡的导航控制器返回顶视图控制器:

    - (UIViewController*)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
    {
        UITabBarController *masterVC = splitViewController.viewControllers[0];
    
        if ([(UINavigationController*)masterVC.selectedViewController viewControllers].count > 1)
            return [(UINavigationController*)masterVC.selectedViewController popViewControllerAnimated:NO];
        else
            return nil; // Use the default implementation
    }
    

    有了这个解决方案,一切都会推送到导航堆栈,并且还可以在iPad / 6格局上正确更新详细视图 .

  • 1

    我想出了如何将细节放到master的UINavigationController上,而不是通过UITabBarController以模态方式呈现它 .

    使用 UISplitViewControllerDelegate 方法

    - splitViewController:showDetailViewController:sender:
    

    如果UISplitViewController折叠,请获取主控导航控制器并将详细视图推送到此导航控制器:

    - (BOOL)splitViewController:(UISplitViewController *)splitViewController
       showDetailViewController:(UIViewController *)vc
                         sender:(id)sender {
        NSLog(@"UISplitViewController collapsed: %d", splitViewController.collapsed);
    
        // TODO: add introspection
        if (splitViewController.collapsed) {
            UITabBarController *master = (UITabBarController *) splitViewController.viewControllers[0];
            UINavigationController *masterNavigationController = (UINavigationController *)master.selectedViewController;
    
            // push detail view on the navigation controller
            //[masterNavigationController pushViewController:vc animated:YES];
            // push was not always working (see discussion in answer below), use showViewController instead
            [masterNavigationController showViewController:vc sender:sender];
    
            return YES;
        }
    
        return NO;
    }
    
  • 8

    当我实现完全相同的UI结构应用程序时,我很欣赏这个讨论主题,并且更适合iPhone 6 Plus旋转和iPad多任务处理(Slide Over / Split View,iOS 9或更高版本) .

    我们已经在GitHub indievox-inc/TabBarSplitViewController上开源了完整的解决方案(自适应UISplitViewController和UITabBarController作为主视图控制器) . 谢谢!

  • 4

    我在Swift中实现了@Dreaming In Binary的答案:

    func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool {
        let masterVC = splitViewController.viewControllers[0] as UITabBarController
    
        if splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact {
            masterVC.selectedViewController?.showViewController(vc, sender: sender)
        } else {
            splitViewController.viewControllers = [masterVC, vc]
        }
    
        return true
    }
    
    func splitViewController(splitViewController: UISplitViewController, separateSecondaryViewControllerFromPrimaryViewController primaryViewController: UIViewController!) -> UIViewController? {
        let masterVC = splitViewController.viewControllers[0] as UITabBarController
    
        if let navController = masterVC.selectedViewController as? UINavigationController {
            if navController.viewControllers.count > 1 {
                return navController.popViewControllerAnimated(false)
            }
        }
        return nil
    }
    

相关问题