iPhone上的纵向UISplitViewController显示细节VC而不是主

我在Xcode 6中使用通用故事板,面向iOS 7及更高版本。 我已经实现了一个UISplitViewController ,它现在在运行iOS 8的iPhone上本机支持,而且Xcode会自动将它UISplitViewController移植到iOS 7.它工作得很好,除非在iPhone上纵向运行iOS 8时启动应用程序,分割视图的细节当我期望首先看到主视图控制器时,显示视图控制器。 我相信这是iOS 8的一个bug,因为当你在iOS 7上运行应用程序时,它正确地显示了主视图控制器。 但iOS 8现在是通用汽车,这仍然在发生。 如何设置它,以便当拆分视图控制器将被折叠(只有一个视图控制器显示在屏幕上),当显示拆分视图控制器时,它显示主视图控制器而不是细节?

我在Interface Builder中创build了这个分割视图控制器。 分屏视图控制器是标签栏控制器中的第一个视图控制器。 主控和详细VC都是内置表格视图控制器的导航控制器。

噢,这让我头痛几天,不知道该怎么做。 最糟糕的部分是创build一个新的Xcode的iOS项目与主细节模板工作得很好。 幸运的是,最终,这个小事实就是我如何find解决scheme。

有一些post,我发现这个解决scheme是在primaryViewControllerForCollapsingSplitViewController:上实现新的primaryViewControllerForCollapsingSplitViewController:方法。 我试过了,无济于事。 苹果在似乎工作的主 – 细节模板中做的是实现新的(深呼吸说这一切) splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:委托方法(同样在UISplitViewControllerDelegate )。 根据文档 ,这种方法:

要求代理调整主视图控制器并将辅助视图控制器合并到折叠界面中。

请务必阅读该方法的讨论部分以获取更多具体的细节。

苹果公司处理的方式是:

 - (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 { return NO; } } 

这个实现基本上做到以下几点:

  1. 如果secondaryViewController是我们所期望的(一个UINavigationController ),它显示了我们期望的( DetailViewController – 你的视图控制器),但没有模型( detailItem ),那么“ Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
  2. 否则,返回“ NO ”让分割视图控制器尝试并将辅助视图控制器的内容合并到折叠界面中

对于纵向的iPhone来说,结果如下(纵向开始或旋转到纵向 – 或更精确的紧凑尺寸等级):

  1. 如果你的观点是正确的
    • 并有一个模型,显示详细的视图控制器
    • 但没有模型,显示主视图控制器
  2. 如果你的观点不正确
    • 显示主视图控制器

清除泥浆。

这里是Swift接受的答案。 只需创build这个子类,并将其分配给您的故事板中的splitViewController。

 //GlobalSplitViewController.swift import UIKit class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() self.delegate = self } func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController!, ontoPrimaryViewController primaryViewController: UIViewController!) -> Bool{ return true } } 

马克S的迅捷版本的正确答案

如苹果的Master-Detail模板所提供的。

 func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController, ontoPrimaryViewController primaryViewController:UIViewController) -> Bool { guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false } if topAsDetailController.detailItem == nil { // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. return true } return false } 

澄清

(Mark S说的有点混乱)

这个委托方法被称为splitViewController: collapseSecondaryViewController: ontoPrimaryViewController:因为这就是它的作用。 当更改为更小的宽度尺寸时(例如,将手机从横向旋转到纵向时),需要将分离视图控制器折叠为其中一个。

这个函数返回一个布尔值来决定是否应该折叠Detail并显示Master。

所以在我们的情况下,我们会根据是否有细节select决定。 我们如何知道我们的细节是否被选中? 如果我们遵循Apple的Master-Detail模板,那么详细信息视图控制器应该有一个可选的具有详细信息的variables,所以如果它没有(.None),那么还没有select任何东西,我们应该显示Master,以便用户可以select一些东西。

而已。

  #import <UIKit/UIKit.h> @interface SplitProductView : UISplitViewController<UISplitViewControllerDelegate> @end 

.M:

 #import "SplitProductView.h" #import "PriceDetailTableView.h" @interface SplitProductView () @end @implementation SplitProductView - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.delegate = self; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ - (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController { if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[PriceDetailTableView class]] //&& ([(PriceDetailTableView *)[(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 { return NO; } } @end 

如果你没有默认值来显示详细的视图控制器,你可以简单的删除SplitViewController和故事板中的详细UIViewController之间的默认值。 这将使其始终进入Master View Controller。

这样做的副作用是,不是在横向上看到两个视图,而是在SplitViewController中看到完整大小的一个视图,直到主视图控制器中的Show Detail Segue被触发为止。

我的应用程序是用Swift 2.x编写的,运行良好。 在将其转换为Swift 3.0(使用XCode转换器)之后,它将首先显示细节,而不是纵向模式下的主控。 问题是函数splitViewController的名称不会更改为匹配新的UISplitViewControllerDelegate。

手动更改该function的名称后,我的应用程序现在可以正常工作:

 func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false } if topAsDetailController.game == nil { // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. return true } return false } 

从文档中 ,你需要使用一个委托来告诉UISplitViewController 不要把详细视图合并到“折叠界面”(即你的案例中的“肖像模式”)。 在Swift 4中,为其实现的委托方法已被重命名为:

 func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { return true } 

在我看来,你应该解决这个问题更通用。 您可以inheritanceUISplitViewController并在embedded视图控制器中实现协议。

 class MasterShowingSplitViewController: UISplitViewController { override func viewDidLoad() { super.viewDidLoad() delegate = self } } extension MasterShowingSplitViewController: UISplitViewControllerDelegate { func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController, ontoPrimaryViewController primaryViewController: UIViewController) -> Bool { guard let masterNavigationController = primaryViewController as? UINavigationController, master = masterNavigationController.topViewController as? SplitViewControllerCollapseProtocol else { return true } return master.shouldShowMasterOnCollapse() } } protocol SplitViewControllerCollapseProtocol { func shouldShowMasterOnCollapse() -> Bool } 

UITableViewController中的示例实现:

 extension SettingsTableViewController: SplitViewControllerCollapseProtocol { func shouldShowMasterOnCollapse() -> Bool { return tableView.indexPathForSelectedRow == nil } } 

希望它有帮助。 所以你可以重用这个类,只需要实现一个协议。

对于那些找不到cs193p星期五节目的人:

在Swift 3.1.1创build一个UISplitViewController的子类并实现它的一个委托方法对我来说就像一个魅力:

 class MainSplitViewController: UISplitViewController, UISplitViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() self.delegate = self } func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool { return true } } 

我的故事板

当您需要从Master开始时,只需从SplitView控制器中删除DetailViewController。

 UISplitViewController *splitViewController = (UISplitViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"SETTINGS"]; splitViewController.delegate = self; [self.navigationController presentViewController:splitViewController animated:YES completion:nil]; if (IPHONE) { NSMutableArray * cntlrs = [splitViewController.viewControllers mutableCopy]; [cntlrs removeLastObject]; splitViewController.viewControllers = cntlrs; } 

Xamarin / C#解决scheme

 public partial class MainSplitViewController : UISplitViewController { public MainSplitViewController(IntPtr handle) : base(handle) { } public override void ViewDidLoad() { base.ViewDidLoad(); Delegate = new MainSplitViewControllerDelegate(); } } public class MainSplitViewControllerDelegate : UISplitViewControllerDelegate { public override bool CollapseSecondViewController(UISplitViewController splitViewController, UIViewController secondaryViewController, UIViewController primaryViewController) { return true; } } 
Interesting Posts