3
votes

In a Universal App I can't find a way to always show (and only) the master controller, even on iPhone 6 Plus in landscape rotation.

What I want to achieve is to see UISplitViewController in action only on the iPad and NOT on the iPhone, don't know if it's possible

delegate methods doesn't help:

func splitViewController(svc: UISplitViewController, shouldHideViewController vc: UIViewController, inOrientation orientation: UIInterfaceOrientation) -> Bool {
        return false
    }

    func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController, ontoPrimaryViewController primaryViewController: UIViewController) -> Bool {
        return true
    }
2

2 Answers

6
votes

You need to override the trait collection of your UISplitViewController to always have a compact size class. To do so you need to insert a container view controller as the parent of your UISplitViewController:

  1. Embed your UISplitViewController into a ContainerViewController
  2. Add the following code into your container view controller subclass to override the trait collection of your child view controller:

    class ContainerVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        performOverrideTraitCollection()
    }
    
    private func performOverrideTraitCollection() {
        for childVC in self.childViewControllers {
            setOverrideTraitCollection(UITraitCollection(horizontalSizeClass: .Compact), forChildViewController: childVC)
        }
    }}
    

Great explanation in Building Adaptive Apps with UIKit (WWDC 2014)

0
votes

Terry's answer works great! Here it is updated to Swift 5 and to work only on iPhone devices, not iPad:

class ContainerVC: UIViewController {

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        if UI_USER_INTERFACE_IDIOM() != .pad {
            performOverrideTraitCollection()
        }
    }

    private func performOverrideTraitCollection() {
        for childVC in self.children {
            setOverrideTraitCollection(UITraitCollection(horizontalSizeClass: .compact), forChild: childVC)
        }
    }
}

Update For iOS 13

The code above no longer works on iOS 13. Use the following instead in the ContainerVC class:

override func overrideTraitCollection(forChild childViewController: UIViewController) -> UITraitCollection? {
    if UIDevice.current.userInterfaceIdiom != .pad {
        return UITraitCollection(horizontalSizeClass: .compact)
    } else {
        return super.traitCollection
    }
}