Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UISplitViewController: how to force showing the master viewcontroller

I am using a UISplitViewController, with the master and the detail viewcontrollers, without UINavigationControllers.

In some cases (for example when clicking on a universal link), I would like to force the app to always show the master viewcontroller.

How can I do that?

Is there a way to switch back from detail to master programmatically?

like image 805
Daniele B Avatar asked Nov 22 '16 08:11

Daniele B


4 Answers

The split view controller is a beast, and the documentation is confusing. It is best understood by considering it as operating in two different modes: collapsed or not. Collapsed mode applies when the split view is presented in a horizontally compact view (i.e. iPhone), otherwise it is not collapsed (i.e. iPad).

The property preferredDisplayMode only applies if the view is NOT collapsed (i.e. iPad), and you can use this to select the master or detail view.

In collapsed mode, unless you are using navigation controllers, the original master view may be discarded:

After it has been collapsed, the split view controller reports having only one child view controller in its viewControllers property. The other view controller is collapsed into the other view controller’s content with the help of the delegate object or discarded temporarily

But it is much better to use navigation controllers, as the split view controller is designed to work in conjunction with them:

The split view controller knows how to adjust the interface in more intuitive ways. It even works with other container view controllers (like navigation controllers) to present view controllers.

If you are using navigation controllers then the original master view may be at the bottom of the navigation stack:

In a horizontally compact environment, the split view controller acts more like a navigation controller, displaying the primary view controller initially and pushing or popping the secondary view controller as needed

So you can do something like this:

if split.isCollapsed,
   let nav = split.viewControllers[0] as? UINavigationController
{
   nav.popToRootViewController(animated:false)
} else {
   split.preferredDisplayMode = .allVisible 
}

(It can get even more complicated if your master view pushes views in master as well as showing detail views. This code will pop to the root of the master view navigation stack)

like image 132
Dale Avatar answered Nov 16 '22 01:11

Dale


You can set the preferredDisplayMode

self.splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.allVisible

Or if you are looking for something like a toggle action:

extension UISplitViewController {
   func toggleMasterView() {
      let barButtonItem = self.displayModeButtonItem
      UIApplication.shared.sendAction(barButtonItem.action!, to: barButtonItem.target, from: nil, for: nil)
   }
}

Usage:

self.splitViewController?.toggleMasterView()
like image 24
zombie Avatar answered Nov 15 '22 23:11

zombie


You can define a custom UISplitViewController and assign it to your split view in storyboard:

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
    }
}
like image 36
Saeed Ir Avatar answered Nov 16 '22 00:11

Saeed Ir


My solution is to swap the position of your primary and secondary ViewControllers if user is using an iPad. Then set preferredDisplayMode = .primaryHidden. Example code below.

splitViewVieController = UISplitViewController()
let isIphone = UIDevice.current.userInterfaceIdiom == .phone
splitViewVieController.viewControllers = isIphone ? [primaryNavController, seconaryNavController] : [seconaryNavController, primaryNavController]
splitViewVieController.preferredDisplayMode = .primaryHidden

We can change the position or width of the primary ViewController if needed.

splitViewVieController.maximumPrimaryColumnWidth = splitViewVieController.view.bounds.width
splitViewVieController.preferredPrimaryColumnWidthFraction = 0.5
splitViewVieController.primaryEdge = .trailing
like image 30
Jeffrey Chang Avatar answered Nov 16 '22 00:11

Jeffrey Chang