打开UISplitViewController到主视图而不是详细信息

时间:2015-04-08 05:34:44

标签: ios objective-c swift uisplitviewcontroller

我有一个带有目标iPhone 6应用程序的拆分视图界面。在第一次启动应用程序时,它将打开详细信息视图;我希望它能打开Master View。我试过了:

self.splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.PrimaryOverlay

其他地方(Prior StackOverFlow Question)建议但它似乎没有做任何事情,并且在发布时不会打开主视图。我还尝试将以下行添加到AppDelegate中:

splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:

但是尽管回归真或假(Another Prior Stack Overflow Question)我没有成功。

我确实在Xcode中启动了示例Master-Detail应用程序,并根据splitViewController加载到Master视图:call returns false;但是,我不确定如何在更复杂的布局中完成这项工作。

9 个答案:

答案 0 :(得分:47)

夫特

UISplitViewController display master view above detail in portrait orientation不是关于显示主视图,而是关于在主视图下方以全宽显示详细信息视图。

UISplitViewController in portrait on iPhone shows detail VC instead of master是关于崩溃机制的原则。

本答案致辞:

  • 主人→明细 (紧凑宽度)
    • iPhone 4s,5,5s,SE,6,6s,7(任意方向)
    • iPod Touch
    • 任何iPhone Plus(肖像)
  • 并排 (所有其他尺寸)
    • ipad公司
    • 任何iPhone Plus(风景)

您必须设置preferredDisplayMode。你想要的是 .primaryVisible ,如果它存在的话!如果只有1个视图符合(紧凑宽度),则使用.allVisible,iOS会选择Detail;在该尺寸中,以下代码将选择Master

诀窍是将{em>两者 preferredDisplayMode更改为.allVisible 以在true中返回collapseSecondary:onto

class PrimarySplitViewController: UISplitViewController,
                                  UISplitViewControllerDelegate {

    override func viewDidLoad() {
        self.delegate = self
        self.preferredDisplayMode = .allVisible
    }

    func splitViewController(
             _ splitViewController: UISplitViewController,
             collapseSecondary secondaryViewController: UIViewController,
             onto primaryViewController: UIViewController) -> Bool {
        // Return true to prevent UIKit from applying its default behavior
        return true 
    }
}

答案 1 :(得分:7)

第1步 - 打开MasterViewController

第2步 - 确保表视图具有UISplitViewControllerDelegate协议。例如:

class ListVC: UITableViewController,UISplitViewControllerDelegate {}

第3步 - 在ViewDidLoad中添加

splitViewController?.delegate = self

第4步 - 然后重写此方法,说主视图控制器应始终折叠到详细视图控制器上:

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

答案 2 :(得分:6)

iOS 14

我没有收到splitViewController(_:collapseSecondary:onto:)的回调,而是使用了以下新方法。

func splitViewController(_ svc: UISplitViewController, topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
    return .primary
}

答案 3 :(得分:4)

  

首次启动应用程序时,它会打开详细信息视图;我希望它打开主视图

假设你只想在第一次发射时,但并非总是如此;例如,在主视图显示空数据集的情况下;然后解决方案就像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
}

答案 4 :(得分:0)

这是一个古老的问题,答案都不是针对目标C的,即使我移植了Swift答案,也没有一个对我有用。一个是由@SwiftArchitect关闭的。

但是他建议将内容模式设置为.allVisible(在Objective C中为UISplitViewControllerDisplayModeAllVisible)-这样可以使主视图始终显示,将视图分为一侧,另一侧为细节。挺不错的,但是OP专门要求在初次启动时显示主视图,这是我需要做的。

更改是将UISplitViewControllerDisplayModePrimaryOverlay用作显示模式。

此答案适用于Xcode 9.4.1,部署目标11.4。

这是MasterViewController.h-您需要在协议声明中添加UISplitViewControllerDelegate:

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import "MasterDetailDemo+CoreDataModel.h"

@class DetailViewController;

@interface MasterViewController : UITableViewController
<UISplitViewControllerDelegate,
NSFetchedResultsControllerDelegate>

@property (strong, nonatomic) DetailViewController *detailViewController;

@property (strong, nonatomic) NSFetchedResultsController<Event *> *fetchedResultsController;
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;

@end

然后在您的MasterViewController.m中,您需要在ViewDidLoad中设置拆分视图控制器委托和内容模式,并跟随@SwiftArchitect的答案一起添加拆分视图控制器委托方法:

- (void)viewDidLoad {

    [super viewDidLoad];

    // needed to "slide out" MasterView on startup on iPad
    self.splitViewController.delegate = self;
    self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;

    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];

    self.navigationItem.rightBarButtonItem = addButton;

    self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}

// split view delegate method
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
    return true;
}

注意:经过一些测试,我发现拆分视图委托方法和拆分视图协议不是必需的。没有它,它的工作原理似乎完全相同。也许这是自最初提出并回答问题以来iOS更改的结果。

通过将这一行放入我的ViewDidLoad方法中,我就可以正常工作

self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;

答案 5 :(得分:0)

或者仅继承UISplitViewController并在情节提要中使用这个新类(基于SwiftArchitect的答案):

class MasterShowingSplitViewController :UISplitViewController, UISplitViewControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.delegate = self
        self.preferredDisplayMode = .allVisible
    }

    func splitViewController(
        _ splitViewController: UISplitViewController,
        collapseSecondary secondaryViewController: UIViewController,
        onto primaryViewController: UIViewController) -> Bool {
        // Return true to prevent UIKit from applying its default behavior
        return true
    }
}

答案 6 :(得分:0)

Swift 5 ,iOS 13

我发现其他答案很有用,但不完全是,因为它们在iPad或iPhone上表现出了我想要的行为,但并没有同时出现。

下面的解决方案是我用来做的:

iPhone:主视图始终首先出现

iPad Portrait:总是显示细节,但要覆盖主视图;详细信息是全屏显示(不仅是母版显示)

iPad Landscape:大师总是在左边,细节总是在右边

class RootSplitViewController: UISplitViewController {
    override func viewDidLoad() {
        if UIDevice.current.userInterfaceIdiom == .pad {
            self.preferredDisplayMode = .automatic
        }
        else {
            self.preferredDisplayMode = .allVisible
        }
        self.delegate = self
    }
}

extension RootSplitViewController: UISplitViewControllerDelegate {
    func splitViewController(_ splitViewController: UISplitViewController,
                             collapseSecondary secondaryViewController:UIViewController,
                             onto primaryViewController:UIViewController)
        -> Bool
    {
        if AppState.instance.currentSelectedEvent == nil {
            // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
            return true
        }
        else {
            return false
        }
    }
}

答案 7 :(得分:0)

iOS 14

WWDC 2020 - Build for iPad中,您可以通过选中属性检查器中的使用单独的视图控制器,为紧凑宽度类添加特定的视图控制器(例如,纵向iPhone,纵向滑行iPad)的SplitViewController。

enter image description here

因此,您可以通过设置关系segue将任何视图控制器设置为所需的初始视图控制器。

enter image description here enter image description here

答案 8 :(得分:0)

iOS 14 -- 两列模式更新

我为此苦苦挣扎了一段时间,最终发现拆分视图控制器已在 iOS14 中重新设计,因此上述答案都不再相关。

我建议从这篇文章开始here

但如果您正在寻找快速解决方案:

  • 您需要在拆分视图控制器上设置“紧凑视图控制器”关系。您可以通过右键单击拆分视图控制器并将新关系拖动到您希望以紧凑模式显示的视图控制器来完成此操作。
  • 我的应用程序有一个 TableView,在紧凑模式下,我想在点击单元格时推送一个 Detail View Controller。在新的 iOS 14 SplitView 控制器中,这必须手动完成。为此,我将以下内容添加到 didSelectRowAt 函数中:
        // If we are in compact mode, we need to push the detail view controller
        if let splitViewController = splitViewController {
            if splitViewController.isCollapsed {
                let shipmentDetailViewController = storyboard?.instantiateViewController(identifier: "shipmentDetailViewController") as! ShipmentDetailViewController
                shipmentDetailViewController.shipment = selectedShipment
                self.navigationController?.pushViewController(shipmentDetailViewController, animated: true)
            }
        }