IOS8 SplitVC + TabBarController + NavigationController [英] IOS8 SplitVC + TabBarController + NavigationController

查看:175
本文介绍了IOS8 SplitVC + TabBarController + NavigationController的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm doing a universal App using size classes and I'm trying to use a SplitView with a TabBarController in the Master/Primary View. Before adding the splitView all worked fine, but now the App crashes (the reason depends on the hierarchy of the views).

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

So I tried the same storyboard starting from Apple SplitView template and add a TabBarController on its Master/primary view... same problem.

层次结构 - TabBarController中的嵌入式主NavigationController:
SplitVC(主)> TabBarController > NavigationController> TableView
SplitVC(详细信息)> NavigationController>查看

Hierarchy - Embedded master NavigationController in TabBarController: SplitVC (Master) > TabBarController > NavigationController > TableView SplitVC (Detail) > NavigationController > View

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

Added this code in AppDelegate.m (as seen here stackoverflow questions ios8-tabbarcontroller... to prevent DetailView being presented modally):

- (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中进行模拟,在这种情况下,以纵向开始并选择一行后,如果您在横向旋转,我会将详细视图视为主要和次要视图。

It works fine... unless you simulate in iPhone6 Plus, in that case, after starting in portrait and selecting a row, if you rotate in landscape I see the detail view as primary AND secondary view.

不使用iPhone以纵向方式添加此代码详细视图以模态方式呈现,当然没有导航按钮。

Without adding this code in portrait orientation with iPhones the detail view is presented modally and of course without navigation buttons.

编辑

EDIT

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

After different tries and with some external helps I've made some steps forward the solution.

短版 (请参阅Long Version以了解为什么必须这样做)

Short version (See Long Version to know why you have to do this)

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

A correct solution to the problem is to subclass TabBarController and make it support some methods:

@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保留为前一个选项卡的那个)然后以纵向旋转,应用程序崩溃。

Now I have a problem with viewControllers stack: with the iPhone6Plus (the only one supporting both horizontal regular and compact) the App crash if, when in landscape, you change tab without selecting a row (so the detailView remain the one for the previous tab) and then rotate in portrait.

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


长版本(SplitViewController行为)

Long version (SplitViewController behaviour)

通常,拆分视图控制器和导航控制器一起工作
,以确保从拆分中包含的视图控制器调用-showDetailViewController:sender:
查看
控制器导致新的详细信息视图控制器被推送到
导航堆栈(当处于水平紧凑的环境中时)。为了
这样做,UISplitViewController重写
-showDetailViewController:sender:并且,如果是水平紧凑的,则调用其主视图控制器的-showViewController:sender:方法。
UINavigationController覆盖-showViewController:sender:和
将传入的视图控制器推送到导航堆栈。

Normally a split view controller and a navigation controller work together to ensure that a call to -showDetailViewController:sender: from a view controller that is contained within the split view controller results in the new detail view controller being pushed onto the navigation stack (when in a horizontally compact environment). To do this, UISplitViewController overrides -showDetailViewController:sender: and, if horizontally compact, calls its master view controller's -showViewController:sender: method. UINavigationController overrides -showViewController:sender: and pushes the incoming view controller onto the navigation stack.

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

UITabBarController however does not override -showViewController:sender: and so it inherits the default implementation which presents the incoming view controller modally. To work around this I have to subclass UITabBarController and override -showViewController:sender: to forward to the tab bar controller's selectedViewController if the selectedViewController is a navigation controller.

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

Furthermore, when a split view controller transitions from a compact to horizontal size class to a regular horizontal size class, the split view controller first sends a -splitViewController:separateSecondaryViewControllerFromPrimaryViewController: message to its delegate. The delegate can implement this method and handle the separation itself, returning the detail view controller. If the delegate does not implement this method, or if the implementation returns nil, the split view controller sends a -separateSecondaryViewControllerForSplitViewController: message to its primary view controller. The primary view controller should implement this method to handle the separation. The UINavigationController does implement -separateSecondaryViewControllerForSplitViewController:. It's implementation pops the top view controller off the navigation stack and returns it. Because I am using a tab bar controller as the primary view controller, I must implement -separateSecondaryViewControllerForSplitViewController: and handle the separation by myself.

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

Also I need to implement my own collapsing logic. When a split view controller transitions from a regular to horizontal size class to a compact horizontal size class, the split view controller first sends a -splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: message to its delegate. The delegate can implement this method and handle the collapse itself. If the delegate does not implement this method, the split view controller sends a -collapseSecondaryViewController:forSplitViewController: message to its primary view controller. The primary view controller should implement this method to handle the separation.

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

UINavigationController does implement -collapseSecondaryViewController:forSplitViewController:. It's implementation pushes the secondary view controller onto the navigation stack. Because I am using a tab bar controller as the primary view controller, I must implement -collapseSecondaryViewController:forSplitViewController: and handle the collapse by myself.


推荐答案

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

So, I found something that works, even if is not the standard behaviour:

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

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

That is equivalent to return always YES in the splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: delegate method. Like this you always discard the secondary controller. Hope this can help someone.

这篇关于IOS8 SplitVC + TabBarController + NavigationController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆