25

I have an XCode iPad project using a navigation controller. I tried to get a button to push a UISplitViewController to the navigation stack, but got this error:

Split View Controllers cannot be pushed to a Navigation Controller

Turns out UISplitViewController doesn't play nicely with UINavigationController. However, I still need to show the split view controller when this button is clicked. How do I do this? And, also important, how do I make a back button so the user can be returned to the navigation controller?

Ian Henry
  • 22,255
  • 4
  • 50
  • 61
Theron Luhn
  • 3,974
  • 4
  • 37
  • 49

4 Answers4

32

To display a SplitViewController you'll need to use setRootViewController. This is because a SplitViewController needs to be the root view controller.

From Apple's Documentation:

A split view controller must always be the root of any interface you create. In other words, you must always install the view from a UISplitViewController object as the root view of your application's window. The panes of your split-view interface may then contain navigation controllers, tab bar controllers, or any other type of view controller you need to implement your interface.

To get back you'll need to use setRootViewController to go back to the earlier page. I ran into this problem when I converted my iPhone app to universal, and ended up using a navigation controller for the iPhone and setRootViewController for the iPad version. It's a bit of a bummer because you can't animate it nicely without a bit of fudging.

Community
  • 1
  • 1
glenstorey
  • 5,134
  • 5
  • 39
  • 71
  • How would I use setRootViewController? Google tells me it's a method of UIWindow, but I can't figure out where to find a UIWindow instance. – Theron Luhn Apr 05 '12 at 16:29
  • 3
    You need to grab it as a property from your app delegate, like this: MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; and then [appDelegate.window setRootViewController:shareSelectViewController]; – glenstorey Apr 05 '12 at 19:58
  • To get the current UIWindow, just use `view.window`. – Ely Jun 20 '22 at 11:46
4

One workaround if you still need to navigate to splitView is to create an empty UIViewController and add the splitViewController as a child

/// This should be in your parent controller
/// that you to navigate your splitView
func navigateToSplit() {

    let container = UIViewController()
    let splitView = MySplitViewController() // ===> Your splitViewController
    container.addAsChildViewController(type: splitView, attached: container.view)
    navigationController?.pushViewController(container, animated: true)
}


extension UIViewController {
    /// this add a child controller to the view of another controller
    func addAsChildViewController(type controller: UIViewController, attached toView: UIView) {
        
        // Add Child View Controller
        addChild(controller)
        
        // Add Child View as Subview
        toView.addSubview(controller.view)
        
        // Configure Child View
        controller.view.frame = toView.bounds
        controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        
        // Notify Child View Controller
        controller.didMove(toParent: self)
        
    }
}


Siempay
  • 876
  • 1
  • 11
  • 32
  • getting error while using the above code : Value of type 'UIViewController' has no member 'addAsChildViewController' – Baadshah Sep 21 '21 at 10:43
  • add this func `func addAsChildViewController` as an extension in `UIViewController` – Siempay Sep 21 '21 at 15:02
2

Pushing a split view controller through navigation controller is not possible, but there is a alternative that get the job done

You can create a view controller and add the split view controller as a child and then you can push that created view controller through the navigation controller. It will show your split view controller and you can work with both master and detail.

*remember to add the yoursplitviewcontroller class to custom class in storyboard

note splitcontroller -> (master, detail)

let splitVC = getViewController(storyBoardName: "story board name", viewControllerName: "split view controller identifier") as! yoursplitviewcontroller
        view.addSubview(splitVC.view)
        view.bounds = splitVC.view.bounds
        addChild(splitVC)

func getViewController(storyBoardName: String, viewControllerName: String) -> UIViewController{
        let storyBoard = UIStoryboard(name: storyBoardName, bundle: nil)
        return storyBoard.instantiateViewController(identifier: viewControllerName)
    }
gnat
  • 6,213
  • 108
  • 53
  • 73
Malith Kuruwita
  • 594
  • 1
  • 9
  • 14
0

I added a 6th tab containing a SplitView, to my application. On iPad the new tab worked fine when selected, but on iPhone the new tab was moved to the "More…" tab and when selected produced the "Split View Controllers cannot be pushed to a Navigation Controller <UIMoreNavigationController:" message.

I solved the problem by moving the new tab so that it could not fall into the "More…" tab.

A more in depth discussion of the problem can be found at:

Tab Bar Controller with seven tabs, Five tabs lead to Split View Controllers