Ios iPhone上肖像中的UISplitViewController显示了VC的细节,而不是master

Ios iPhone上肖像中的UISplitViewController显示了VC的细节,而不是master,ios,interface-builder,ios8,uisplitviewcontroller,master-detail,Ios,Interface Builder,Ios8,Uisplitviewcontroller,Master Detail,我在Xcode 6中使用通用故事板,目标是iOS 7及以上版本。我已经实现了一个UISplitViewController,它现在在运行ios8的iPhone上本机支持,Xcode将自动为ios7支持它。它工作得非常好,除了在iPhone上以运行iOS 8的纵向模式启动应用程序时,当我第一次看到主视图控制器时,会显示分割视图的详细视图控制器。我认为这是iOS 8的一个bug,因为当你在iOS 7上运行应用程序时,它会正确地显示主视图控制器。但iOS 8现在是通用的,而且这种情况还在发生。如何设置

我在Xcode 6中使用通用故事板,目标是iOS 7及以上版本。我已经实现了一个
UISplitViewController
,它现在在运行ios8的iPhone上本机支持,Xcode将自动为ios7支持它。它工作得非常好,除了在iPhone上以运行iOS 8的纵向模式启动应用程序时,当我第一次看到主视图控制器时,会显示分割视图的详细视图控制器。我认为这是iOS 8的一个bug,因为当你在iOS 7上运行应用程序时,它会正确地显示主视图控制器。但iOS 8现在是通用的,而且这种情况还在发生。如何设置它,以便在拆分视图控制器将要折叠时(屏幕上仅显示一个视图控制器),在显示拆分视图控制器时,显示主视图控制器而不是详细信息


我在Interface Builder中创建了此拆分视图控制器。拆分视图控制器是选项卡栏控制器中的第一个视图控制器。主VCs和详细VCs都是内置表视图控制器的导航控制器。

哦,天哪,这让我头疼了好几天,我想不出怎么做。最糟糕的是,用主细节模板创建一个新的Xcode iOS项目效果很好。幸运的是,最后,这个小事实就是我如何找到解决方案的

我发现一些帖子建议解决方案是在
UISplitViewControllerDelegate
上实现新的
primaryViewControllerForCollapsingSplitViewController:
方法。我试过了,但没有用。苹果在主细节模板中所做的似乎很有效的是实现新的(深吸一口气说这一切)
splitViewController:collapseSecondaryViewController:ontopprimaryviewcontroller:
委托方法(再次在
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;

    }
}
此实现基本上执行以下操作:

  • 如果
    secondaryViewController
    是我们期望的(一个
    UINavigationController
    ),并且它显示了我们期望的(一个
    DetailViewController
    --您的视图控制器),但是没有模型(
    detailItem
    ),那么“
    返回YES,表示我们已通过不采取任何行动来处理崩溃;辅助控制器将被丢弃。
  • 否则,返回“
    NO
    ,让拆分视图控制器尝试将次视图控制器的内容合并到折叠的界面中”
  • iPhone的纵向(从纵向开始或旋转到纵向——或者更准确地说是压缩尺寸等级)的结果如下:

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

  • 清除为mud。

    如果没有默认值显示在细节视图控制器中,只需删除故事板中SplitViewController和细节UIViewController之间的默认分段即可。
       #import <UIKit/UIKit.h>
    
        @interface SplitProductView : UISplitViewController<UISplitViewControllerDelegate>
    
    
    
    
        @end
    
    这将使它始终首先进入主视图控制器


    这样做的副作用是,在启动主视图控制器中的Show Detail Segue之前,您不会在横向视图中看到两个视图,而是在SplitViewController中看到一个全尺寸视图。

    这是Swift中公认的答案。只需创建此子类,并将其分配给情节提要中的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正确答案的快速版本 由苹果的主细节模板提供

    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
    }
    

    澄清 (马克·S说的有点让人困惑)

    此委托方法称为
    splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
    ,因为它就是这样做的。当更改为更紧凑的宽度大小时(例如,当将手机从横向旋转到纵向时),它只需要将split view控制器折叠为其中一个

    此函数返回一个布尔值,以决定是否折叠细节并显示主视图

    因此,在我们的例子中,我们将根据是否选择了详细信息来决定。我们如何知道是否选择了我们的详细信息?如果我们遵循Apple的主详细信息模板,详细信息视图控制器应该有一个可选变量,该变量包含详细信息,因此如果它为零(.None),尚未选择任何内容,我们应该显示主控形状,以便用户可以选择一些内容


    就这样。

    在我看来,您应该更通用地解决这个问题。您可以将UISplitViewController子类化,并在嵌入式视图控制器中实现协议

    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
        }
    }
    
    希望能有帮助。
    因此,您可以重用该类,只需实现一个协议。

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

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

    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
    }
    

    当需要从主控启动时,只需从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;
    }
    
    从中,您需要使用代理通知
    UISplitViewController
    不要将细节视图合并到“折叠界面”(即您的情况下的“纵向模式”)中
    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;
    }
    
    func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
        return true
    }
    
    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
    } }
    
    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;
        }
    }
    
    //Following code in application didFinishLaunching (inside Application Delegate)
    guard let splitViewController = window?.rootViewController as? UISplitViewController,
                let masterNavVC = splitViewController.viewControllers.first as? UINavigationController,
                let masterVC = masterNavVC.topViewController as? MasterViewController
    else { fatalError() }
    splitViewController.delegate = masterVC
    
    //Following code in MasterViewController class
    extension MasterViewController:UISplitViewControllerDelegate {
        func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
            return true
        }
    }
    
    import UIKit
    
    class GlobalSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.delegate = self
        }
    
        func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
            return true
        }
    
    }
    
    class MySplitViewController: UISplitViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.preferredDisplayMode = .allVisible
        }
    
    }