IOS8 SplitVC + TabBarController + NavigationController
Posted
技术标签:
【中文标题】IOS8 SplitVC + TabBarController + NavigationController【英文标题】: 【发布时间】:2015-07-09 22:44:24 【问题描述】:我正在使用大小类做一个通用应用程序,我正在尝试在主视图/主视图中使用带有 TabBarController 的 SplitView。在添加 splitView 之前一切正常,但现在 App 崩溃(原因取决于视图的层次结构)。
所以我从 Apple SplitView 模板开始尝试了相同的故事板,并在其主视图/主视图上添加了 TabBarController...同样的问题。
层次结构 - TabBarController 中的嵌入式主 NavigationController: SplitVC (Master) > TabBarController > NavigationController > TableView SplitVC(详细)> NavigationController > View
在 AppDelegate.m 中添加了此代码(如此处所示 *** 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: 并且,如果水平紧凑,则调用其主视图控制器的 -showViewController: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: 并自行处理折叠。
【问题讨论】:
【参考方案1】:所以,我发现了一些可行的方法,即使不是标准行为:
- (void)collapseSecondaryViewController:(UIViewController *)secondaryViewController forSplitViewController:(UISplitViewController *)splitViewController
[self.selectedViewController.navigationController collapseSecondaryViewController:secondaryViewController forSplitViewController:splitViewController];
这相当于在splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
委托方法中总是返回YES
。像这样,您总是丢弃辅助控制器。
希望这可以帮助某人。
【讨论】:
【参考方案2】:试试这个 sn-p 并告诉我们你的结果。这个 sn-p 从 *** 之外的网站获取 (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
【讨论】:
它不起作用,同样的问题。你试过了吗?它对你有用吗? 你好@Zag,对不起,我忘记了一个水平计数器。我不知道为什么,但有时(在将肖像更改为土地或反之亦然之后)我们有 3 个屏幕而不仅仅是 2 个,我想这只是为了内部操作到鞋屏幕的顺序。上面的代码对我有用。 嗨@Beto,AFAIK SplitViewController 层次结构会根据折叠或分离模式而变化。见this article。我会试试你的解决方案。谢谢。 希望对您有所帮助,如果您发现更好的东西,请写在这里。以上是关于IOS8 SplitVC + TabBarController + NavigationController的主要内容,如果未能解决你的问题,请参考以下文章
在 splitViewController 的 detailView 中设置 barButtonItem 的标题
UINavigationController 在标签栏控制器之前和标签栏控制器之后?