IOS8 SplitVC + TabBarController + NavigationController

时间:2015-07-09 22:44:25

标签: ios objective-c uitabbarcontroller uisplitviewcontroller adaptive-ui

我正在使用大小类进行通用应用程序,并尝试在主/主视图中使用带有TabBarController的SplitView。在添加splitView之前一切正常,但现在App崩溃了(原因取决于视图的层次结构)。

所以我尝试从Apple SplitView模板开始尝试相同的故事板,并在其主/主视图上添加一个TabBarController ......同样的问题。

层次结构 - TabBarController中的嵌入式主NavigationController: SplitVC(Master)> TabBarController> NavigationController>的TableView SplitVC(详情)> NavigationController>图

在AppDelegate.m中添加了此代码(如stackoverflow questions ios8-tabbarcontroller...所示,以防止以模态方式呈现DetailView):

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender {
        NSLog(@"UISplitViewController collapsed: %d", splitViewController.collapsed);

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
    {
        if (splitViewController.collapsed) {
            UITabBarController *master = (UITabBarController *) splitViewController.viewControllers[0];
            UINavigationController *masterNavigationController = (UINavigationController *)master.selectedViewController;
            UINavigationController *destinationNavigationController = (UINavigationController *)vc;

            // push detail view on the navigation controller
            [masterNavigationController pushViewController:[destinationNavigationController.viewControllers lastObject] animated:YES];

            return YES;
        }
    }

    return NO;
}

它运行正常...除非你在iPhone6 Plus中进行模拟,在这种情况下,在以纵向开始并选择一行后,如果你在横向旋转我会看到详细视图作为主要和次要视图。

如果不使用iPhone以纵向方式添加此代码,则会以模态方式显示详细视图,当然也不会显示导航按钮。

修改

经过不同的尝试和一些外在的帮助,我已经向前推进了解决方案。

简短版(请参阅长版以了解您必须执行此操作的原因)

问题的正确解决方案是继承TabBarController,并使其支持一些方法:

@implementation MyTabBarController

- (void)showViewController:(UIViewController *)vc sender:(id)sender
{
    if ([self.selectedViewController isKindOfClass:UINavigationController.class])
        [self.selectedViewController showViewController:vc sender:sender];
    else
        [super showViewController:vc sender:sender];
}

- (UIViewController*)separateSecondaryViewControllerForSplitViewController:(UISplitViewController *)splitViewController
{
    return [self.selectedViewController separateSecondaryViewControllerForSplitViewController:splitViewController];
}

- (void)collapseSecondaryViewController:(UIViewController *)secondaryViewController forSplitViewController:(UISplitViewController *)splitViewController
{
    [self.selectedViewController collapseSecondaryViewController:secondaryViewController forSplitViewController:splitViewController];
}

现在我遇到了viewControllers堆栈的问题:使用iPhone6Plus(唯一一个支持水平常规和紧凑)的应用程序崩溃,如果在横向时,您更改选项卡而不选择行(因此detailView仍然是上一个标签)然后以纵向旋转。

我知道我必须实现正确管理视图堆栈的分离和折叠方法,但我无法弄清楚如何。有人可以提供帮助吗?

  

长版(SplitViewController行为)

     

通常分割视图控制器和导航控制器工作   一起确保调用-showDetailViewController:sender:   来自拆分视图中包含的视图控制器   控制器导致新的细节视图控制器被推入   导航堆栈(在水平紧凑的环境中)。至   这样做,UISplitViewController重写   -showDetailViewController:sender:并且,如果是水平紧凑的,则调用其主视图控制器&#sshowViewController:sender:方法。   UINavigationController重写-showViewController:sender:和   将传入的视图控制器推送到导航堆栈。

     然而,

UITabBarController不会覆盖   -showViewController:sender:所以它继承了默认的实现,它以模态方式呈现传入的视图控制器。   要解决这个问题,我必须继承UITabBarController并重写   -showViewController:sender:如果selectedViewController是导航,则转发到标签栏控制器的selectedViewController   控制器。

     

此外,当分割视图控制器从紧凑型转换时   将水平尺寸类转换为常规水平尺寸类,拆分   视图控制器首先发送一个   -splitViewController:separateSecondaryViewControllerFromPrimaryViewController:   消息给它的代表。委托可以实现此方法和   处理分离本身,返回详细视图控制器。   如果委托没有实现此方法,或者如果   实现返回nil,拆分视图控制器发送一个   -separateSecondaryViewControllerForSplitViewController:消息到其主视图控制器。主视图控制器应该实现   这种方法来处理分离。 UINavigationController确实如此   实现-separateSecondaryViewControllerForSplitViewController:   它的实现将顶视图控制器弹出导航   堆栈并返回它。因为我使用标签栏控制器作为   主视图控制器,我必须实现   -separateSecondaryViewControllerForSplitViewController:并自行处理分离。

     

另外,我需要实现自己的折叠逻辑。当拆分视图时   控制器从常规大小类转换为水平大小类   紧凑的水平尺寸类,拆分视图控制器首先发送一个   -splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:   消息给它的代表。委托可以实现此方法和   处理崩溃本身。如果代表没有实现这一点   方法,拆分视图控制器发送一个   -collapseSecondaryViewController:forSplitViewController:消息到其主视图控制器。主视图控制器应该   实现此方法来处理分离。

     

UINavigationController确实实现了   -collapseSecondaryViewController:forSplitViewController :.它的实现将辅助视图控制器推到了   导航堆栈。因为我使用标签栏控制器作为   主视图控制器,我必须实现   -collapseSecondaryViewController:forSplitViewController:并自行处理崩溃。

2 个答案:

答案 0 :(得分:1)

所以,我发现了一些有效的东西,即使它不是标准行为:

- (void)collapseSecondaryViewController:(UIViewController *)secondaryViewController forSplitViewController:(UISplitViewController *)splitViewController
{
    [self.selectedViewController.navigationController collapseSecondaryViewController:secondaryViewController forSplitViewController:splitViewController];
}

这相当于YES委托方法中始终返回splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:。像这样你总是丢弃辅助控制器。 希望这可以帮助别人。

答案 1 :(得分:0)

试试此片段并告诉我们您的搜索结果。此代码段来自stackOverflow(Craig Marvelley

之外的网站
#pragma mark - Split view
// Update secondaryview with the right screen
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController { 
int tryIt = 0;

if ((IS_IPHONE_6_PLUS) && (isLandscape)) {
    if ([primaryViewController isKindOfClass:[UINavigationController class]]) {
        for (UIViewController *controller in [(UINavigationController *)primaryViewController viewControllers]) {
            tryIt = tryIt + 1;
            if ([controller isKindOfClass:[UINavigationController class]] && ([[(UINavigationController *)controller visibleViewController] isKindOfClass:[yourPosibleScreen01 class]] || [[(UINavigationController *)controller visibleViewController] isKindOfClass:[yourPosibleScreen02 class]]) ) {
                return controller;
            }
            // Sublevel where yo are to select the right screen. You must try with a number depends of how many internal hierarchy. But I believe you need number 2 but try it :) 
            if (tryIt > 2) {
                return controller;
            }
        }
    }
    // Update detail screen
    UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"YourScreenToShow"];
    return toViewController;
}
return nil;
}


 - (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {

     return NO;
}
#pragma mark - Split view