我正在使用Xcode 7(虽然我认为这也适用于6),主要细节模板稍作修改。修改是用UITabBarController替换主UINavigationController。
UITabBarController包含几个UINavigationControllers,它们又与细节UINavigationController相隔。
使用iPhone 6+模拟器,它在横向模式下工作正常(非折叠)。折叠UISplitViewController时,应用程序会停止按预期运行。发生了两件事:
didFinishLaunchingWithOptions
中,splitViewController.viewControllers
数组包含UITabBarController
(主)和UINavigationController
(详细信息)。在didFinishLaunchingWithOptions
和splitViewController:collapseSecondaryViewController:ontoPrimaryViewController
之间的某处,详细信息UINavigationController
已从splitViewController.viewControllers
中删除。如果master和detail都是UINavigationController
个对象,则不会发生这种情况。值得注意的是,在Apple的UISplitViewController
文档中,他们说viewControllers
属性:"当展开拆分视图界面时,此属性包含两个查看控制器;折叠时,此属性只包含一个视图控制器。"在我修改故事板以将UITabBarController作为主文件后,文档中的断言似乎仍然成立,在默认的主 - 详细信息模板中,断言没有保持(即数组中始终有两个viewControllers,无论如何分割视图是折叠还是展开的。)EXC_BAD_ACCESS
崩溃 - 由于某种原因,我也会收到错误:"<Error>: CGImageCreate: invalid image size: 0 x 0."
。香草的唯一变化是&#39;此阶段的模板应用程序将使用包含UINavigationControllers的UITabBarController替换Master UINavigationController,故事板如下所示:
我还注释了MasterViewController.m
中的以下行以防止早期崩溃:
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
我的问题是:
viewControllers
属性的内容会发生变化?我问,因为我认为这与确定为什么细节VC以模态方式呈现而不是被推送相关。我假设,因为在折叠模式下,SplitViewController的行为类似于UINavigationController,当UISplitViewController和详细视图之间存在非UINavigationController时,存在一些困难。我试图了解正在发生的事情,因为如果有一个(或更多),我正试图找到一个正确的方法让它发挥作用。
我使用“二元梦想”的答案并取得了一定的成功。和&#39; HpTerm&#39;。
如果我首先采用Dreaming In Binary的答案(使用该答案中的代码逐字逐句),那么该应用程序的行为几乎与以前相同;我特别注意以下几点:
从纵向视图中选择时,详细视图仍以模态显示;由于我们添加了这种方法(取自前面提到的答案),因此基本上会有一个稍微不同的细节视图呈现路径:
-(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;
}
showViewController
仍会触发detailViewController的模态表示。纵向右上方没有导航按钮,但如果将设备旋转为横向,则详细视图将拍摄整个横向,但我们确实看到使用splitViewController.displayModeButton项设置的navigationItem的leftBarButtonItem。麻烦的是按钮除了显示“扩展”按钮之外绝对没有任何影响。按钮(用于隐藏主视图);如果按下按钮,视图没有任何反应(主视图已经隐藏了),但按钮变为“后退”状态。通常允许您再次显示主视图的样式。在这种情况下,&#39;返回&#39;按下按钮无效。基本上你可以切换到&#39; expand&#39;之间的按钮。和&#39;回来&#39;按下它时没有其他效果。如果您旋转回横向,那么您再次拥有模态显示的详细视图,无法返回到主视图。
<Error>: CGImageCreate: invalid image size: 0 x 0.
,但它没有伴随EXC_BAD_ACCESS崩溃。接下来,是HpTerm在Swift中的解决方案,在我的世界中看起来像这样:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)detailViewController sender:(id)sender
{
UITabBarController * masterViewController = splitViewController.viewControllers[0];
if (splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact)
{
UIViewController * detailViewSubController = ((UINavigationController *)detailViewController).viewControllers[0];
[((UINavigationController *)masterViewController.selectedViewController) pushViewController:(UIViewController *)detailViewSubController animated:NO];
return YES;
}
else
{
return NO;
}
}
因此,在上文中,我们不是尝试使用详细信息showViewController
来UINavigationController
,而是从详细信息DetailViewController
中提取UINavigationController
并实际推送DetailViewController
到主人UINavigationController
。不将细节UINavigationController
推送到主UINavigationController
的原因是抛出异常(如果将任何导航控制器推到另一个导航控制器上,则适用)。
这实际上产生了几乎完美的结果,但并不完全。首先,好位:
现在坏了:
所以这里的问题是,&#39;坏&#39;要更正这一点,以便在纵向选择项目时,旋转回横向将我们带到选定的细节项目?
道歉,这太久了,如果你已经做到这一点,我向你致敬!我也很乐意提出减轻问题的建议,但希望提供足够的细节来突出显示正在发生的事情。
答案 0 :(得分:0)
我仍然愿意接受其他答案,因为有几种方法可以解决这个问题,但有一种方法可以修改Master-Detail App Template的splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
实现。
首先解释一下;在上面问题的最后部分中splitViewController:showDetailViewController:sender:
的实现解决了UI方面的一个(重大)问题。它允许将详细视图推送到主UINavigationController的堆栈,同时保持主UITabBarController
可见并允许导航回主视图。它通过从分割视图控制器的详细导航控制器中取出DetailViewController
并将DetailViewController
推入堆栈,在折叠模式下执行此操作。这与默认的Master-Detail模板不同,因为在该版本中,细节导航控制器被推到主导航控制器上并且仍然可以工作(我只是无法找到一种方法使其在添加后像这样工作UITabBarController
)。完成此操作后,当我们旋转到横向(展开)视图时,一切仍然正常工作(细节导航控制器返回),但是当我们旋转到纵向(折叠)视图时,我们最终返回主视图,即使选择了详细信息项目。
我强制推送详细信息视图(如果有数据要显示),方法是通过从主控制器触发详细视图的segue向splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
添加一个附加条件:
if ([secondaryViewController isKindOfClass:[DetailViewController class]] && [(DetailViewController *)secondaryViewController detailItem] != nil && [primaryViewController isKindOfClass:[UITabBarController class]])
{
UINavigationController * currentMasterNavigationController = ((UITabBarController *)primaryViewController).selectedViewController;
MasterViewController * masterViewController = (MasterViewController *)[currentMasterNavigationController visibleViewController];
[masterViewController performSegueWithIdentifier:@"showDetail" sender:masterViewController];
return YES;
}
完整修改后的功能是:
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController
{
if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]] && ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil))
{
// Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return YES;
}
else if ([secondaryViewController isKindOfClass:[DetailViewController class]] && [(DetailViewController *)secondaryViewController detailItem] != nil && [primaryViewController isKindOfClass:[UITabBarController class]])
{
UINavigationController * currentMasterNavigationController = ((UITabBarController *)primaryViewController).selectedViewController;
MasterViewController * masterViewController = (MasterViewController *)[currentMasterNavigationController visibleViewController];
[masterViewController performSegueWithIdentifier:@"showDetail" sender:masterViewController];
return YES;
}
return NO;
}
这对我来说似乎仍然是一个黑客,但它确实有效。我希望看到一个比这更清晰的答案,它更像默认模板,同时仍允许UITabBarController
答案 1 :(得分:0)
我相信你已经对工作实施有所了解。我花了几周时间才完成它。
Apple的UISplitViewController确实需要一些额外的调整来正确地改变大小类。我已将自适应UISplitViewController与UITabBarController一起作为GitHub indievox-inc/TabBarSplitViewController上开源的主视图控制器,应该值得检查一下。
您可以查看the original implementation,这样可以更轻松地移植到Objective-C代码。
以下主要功能:
// MARK: to Compact Width size class (collapse)
public func primaryViewControllerForCollapsingSplitViewController(splitViewController: UISplitViewController) -> UIViewController? {
if let primaryTabViewController = splitViewController.viewControllers[0] as? UITabBarController,
primaryNavViewController = primaryTabViewController.selectedViewController as? UINavigationController {
let secondaryViewController = splitViewController.viewControllers[1]
if !(secondaryViewController.dynamicType === DetailViewControllerType.Empty) {
dispatch_async(dispatch_get_main_queue()) { // otherwise we may get console error "<Error>: CGImageCreate: invalid image size: 0 x 0."
primaryNavViewController.showViewController(secondaryViewController, sender: secondaryViewController)
}
return primaryTabViewController
}
}
return nil
}
// MARK: to Regular Width size class (separate/expand)
public func splitViewController(splitViewController: UISplitViewController, separateSecondaryViewControllerFromPrimaryViewController primaryViewController: UIViewController) -> UIViewController? {
if let primaryTabViewController = splitViewController.viewControllers[0] as? UITabBarController,
primaryNavViewController = primaryTabViewController.selectedViewController as? UINavigationController {
let primaryTopViewController = primaryNavViewController.topViewController
if let primaryTopViewController = primaryTopViewController {
if ((primaryTopViewController.dynamicType === DetailViewControllerType.General)
|| (primaryTopViewController.dynamicType === DetailViewControllerType.Empty)) {
primaryNavViewController.popViewControllerAnimated(false)
return primaryTopViewController
}
}
}
return DetailViewControllerType.Empty.init()
}
// MARK: override showDetailViewController
public func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool {
let isCompactWidth = (splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact)
if isCompactWidth {
if let primaryTabViewController = splitViewController.viewControllers[0] as? UITabBarController,
primaryViewController = primaryTabViewController.selectedViewController as? UINavigationController {
primaryViewController.showViewController(vc, sender: sender)
return true
}
}
return false
}