UISplitViewController在iPhone上的肖像显示详细VC而不是主

Jor*_*n H 173 interface-builder master-detail uisplitviewcontroller ios ios8

我在Xcode 6中使用通用故事板,目标是iOS 7及更高版本.我已经实现了一个UISplitViewController现在支持运行iOS 8的iPhone本身支持,Xcode将自动向iOS 7后端移植.它运行得非常好,除非你在iPhone上以iOS 8纵向启动应用程序,拆分视图的详细视图我希望第一次看到主视图控制器时显示控制器.我相信这是iOS 8的一个错误,因为当您在iOS 7上运行应用程序时,它会正确显示主视图控制器.但iOS 8现在是通用汽车,而且这种情况仍在发生.如何进行设置以便在拆分拆分视图控制器时(屏幕上只显示一个视图控制器),当显示拆分视图控制器时,它会显示主视图控制器而不是详细信息?

我在Interface Builder中创建了这个拆分视图控制器.拆分视图控制器是标签栏控制器中的第一个视图控制器.主控和详细VC都是导航控制器,其中嵌入了表视图控制器.

小智 234

哦,伙计,这让我头疼了几天,无法弄清楚如何做到这一点.最糟糕的是,使用master-detail模板创建一个新的Xcode iOS项目工作得很好.幸运的是,最后,我找到解决方案的那个小事实.

我发现有一些帖子表明解决方案是实现新primaryViewControllerForCollapsingSplitViewController:方法UISplitViewControllerDelegate.我试过没有用.Apple在主要细节模板中所做的工作似乎是实现新的(深呼吸说出所有这一切)splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:委托方法(再次UISplitViewControllerDelegate).根据文档,这种方法:

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

请务必阅读该方法的讨论部分以获取更具体的详细信息.

Apple处理此问题的方式是:

- (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;

    }
}
Run Code Online (Sandbox Code Playgroud)

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

  1. 如果secondaryViewController是我们期待的(a UINavigationController),并且它显示了我们期望的东西(a 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. 如果您的观点不正确
    • 显示主视图控制器

清除泥土.

  • 很棒的答案!我简单地继承了`UISplitViewController`并始终从该方法返回`YES`,然后只更改了Storyboard中的拆分视图类,因为我总是希望在iPhone上以纵向显示主控.:) (7认同)
  • @ joey的评论适用于设置self.delegate = self; 在viewdidload中!并在.h中添加<UISplitViewControllerDelegate>谢谢! (6认同)
  • 如果“iPhone”处于“纵向”模式,我希望我的主视图控制器被隐藏,因为我有一个默认的细节视图控制器设置。我怎样才能做到这一点。我的 master 和 detail 都是 VC 类型。具体来说,我的细节是 MMDrawerController。请帮忙 (2认同)
  • 我尝试了Joey关于子类化`UISplitViewController`的建议,但发现它不起作用:`splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:`从未被调用过.相反,我复制了Apple的模板并将其放入AppDelagate.这需要在`application didFinishLaunchingWithOptions:`下创建UISplitViewController进行一些更改(我还复制了Apple的模板). (2认同)
  • 这对我来说似乎是正确的答案,因为我遇到了完全相同的问题。但是,由于某种原因,我的 `splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:` 永远不会被调用。看来委托正在正确设置我的应用程序委托的`applicationDidFinishLaunchingWithOptions:` 方法。有没有其他人看到过这个问题并且没有解决这个问题? (2认同)

Cli*_*rum 60

以下是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
  }

}
Run Code Online (Sandbox Code Playgroud)

  • 现在在 Swift 中,无论它是什么`func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, on primaryViewController: UIViewController) -&gt; Bool {` (3认同)
  • 似乎只有在类大小紧凑时才调用委托方法。它在 iPhone 上被调用,而不是在 iPad 肖像上调用,这意味着它不能解决问题,因为 iPad 肖像也处于折叠模式。使用 iOS 12.1 测试 (3认同)
  • 太好了,这很有帮助.但是出现了一个新问题.把我带到大师的后门按钮现在消失了(从未显示过).我怎么得到它?编辑:没关系,想通了自己:-).对于其他用户:在detailView中添加:self.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()self.navigationItem.leftItemsSupplementBackButton = true (2认同)

Niñ*_*ipt 19

Swift版本的Mark S'正确答案

由Apple的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
}
Run Code Online (Sandbox Code Playgroud)

澄清

(Mark S所说的有些令人困惑)

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

此函数返回一个布尔值,以决定是否应折叠Detail并显示Master.

因此,在我们的案例中,我们将根据是否选择了详细信息来决定.我们如何知道我们的细节是否被选中?如果我们遵循Apple的Master-Detail模板,详细视图控制器应该有一个带有详细信息的可选变量,所以如果它是nil(.None),则没有选择任何东西,我们应该显示Master,以便用户可以选择一些东西.

而已.


Ton*_*ony 9

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

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

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
}
Run Code Online (Sandbox Code Playgroud)

  • 对于swift 3,不要忘记将`self.delegate = self`在`viewDidLoad`方法中. (2认同)

oli*_*ito 9

文档中,您需要使用委托来告诉UISplitViewController 不要将详细视图合并到"折叠界面"(即您的情况下的"纵向模式").在Swift 4中,为其实现的委托方法已重命名:

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


Gan*_*ank 8

   #import <UIKit/UIKit.h>

    @interface SplitProductView : UISplitViewController<UISplitViewControllerDelegate>




    @end
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)


小智 7

如果您没有要在详细视图控制器中显示的默认值,您只需删除故事板中SplitViewController和详细信息UIViewController之间的默认segue.这将使它始终首先进入主视图控制器.

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