Open UISplitViewController to Master View rather than Detail

前端 未结 7 1157
北海茫月
北海茫月 2020-12-04 13:14

I have a split-view interface with a target iPhone 6 application. On the first launch of the application, it opens to the Detail View; I would like it to open to the Master

相关标签:
7条回答
  • 2020-12-04 13:45

    On the first launch of the application, it opens to the Detail View; I would like it to open to the Master View

    Assuming you want that only on the first launch, but not always; for example in the case that the Master View shows an empty data set; then the solution is just as the Master-Detail template shows:

    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
    }
    
    0 讨论(0)
  • 2020-12-04 13:51

    Or just inherit from UISplitViewController and use this new class in the storyboard (based on SwiftArchitect's answer):

    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
        }
    }
    
    0 讨论(0)
  • 2020-12-04 13:52

    Swift 5, iOS 13

    I found other answers useful, but not-quite-there in that they produced the behavior I wanted on iPad or iPhone, but not both.

    The solution below is what I used for:

    iPhone: Master view always appears first

    iPad Portrait: detail always appears, but with master overlaying it; detail is full-screen (not just right-of-master)

    iPad Landscape: Master always on left, detail always on right

    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
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-04 13:55

    This is an oldish question and none of the answers were for Objective C, and even when I ported the Swift answers, none worked for me. One was close, by @SwiftArchitect.

    But he recommended setting the content mode to .allVisible (UISplitViewControllerDisplayModeAllVisible in Objective C) - this makes the master view display all the time, splitting the view into master on one side, detail on the other. Which is kinda cool, but the OP asked specifically to display the master view on initial launch, which is what I needed to do.

    The change was to use UISplitViewControllerDisplayModePrimaryOverlay for the display mode.

    This answer is for Xcode 9.4.1, deployment target 11.4.

    Here is MasterViewController.h - you need to add UISplitViewControllerDelegate in the protocols declaration:

    #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
    

    And then in your MasterViewController.m, you need to set the split view controller delegate and the content mode in ViewDidLoad, and following along with @SwiftArchitect's answer, to also add the split view controller delegate method:

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

    NOTE: After some testing, I found that the split view delegate method and the split view protocol was not necessary. Without it, it appears to work exactly the same. Perhaps this is a result of changes in iOS since the question was originally asked and answered.

    I got it working fine just by putting this line in my ViewDidLoad method:

    self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay;
    
    0 讨论(0)
  • 2020-12-04 14:03

    Step 1 - Open MasterViewController

    Step 2 - ensure the table view has the UISplitViewControllerDelegate protocol. Eg:

    class ListVC: UITableViewController,UISplitViewControllerDelegate {}
    

    Step 3 - Add it in ViewDidLoad

    splitViewController?.delegate = self
    

    Step 4 - Then override this method to say the master view controller should always collapse onto the detail view controller:

    func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
        return true
    }
    
    0 讨论(0)
  • 2020-12-04 14:04

    Swift

    UISplitViewController display master view above detail in portrait orientation is not about showing the Master view, it is about presenting the Detail view in full width, underneath the Master view.

    UISplitViewController in portrait on iPhone shows detail VC instead of master is about the principle of the collapse mechanism.

    This present answer addresses:

    • Master → Detail (Compact width)
      • iPhone 4s, 5, 5s, SE, 6, 6s, 7 (any orientation)
      • iPod Touch
      • any iPhone Plus (portrait)
    • side-by-side (all other sizes)
      • iPad
      • any iPhone Plus (landscape)

    You must set preferredDisplayMode. You would want is .primaryVisible if it existed! Using .allVisible, iOS picks Detail if only 1 view fits (Compact width); in that size, the code below will pick Master.

    The trick is to change both the preferredDisplayMode to .allVisible and to return true in collapseSecondary:onto.

    class PrimarySplitViewController: 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 
        }
    }
    
    0 讨论(0)
提交回复
热议问题