0
votes

I have been scratching my head trying to figure out how to do this. If anyone has some insight it would be greatly appreciated. I've attempted to do this using segues and push/presentViewController methods. With pushViewController nothing happens.

Scenario: Split view controller has two navigation controllers connected (one as master, one as detail). The master's navigation controller has a form with various cells that should control what is being displayed in the right hand side detail view when in landscape mode on the iPad. The navigation controller connected to the detail view has storyboard references connected to it (3 of them).

What I want to do: From the master view controller (which is the app menu), I would like to control what is being displayed in the detail view while maintaining navigation bar.

Attempt 1:

let detailVC = self.splitViewController!.viewControllers[1]
let newVC = UIStoryboard(name: "D", bundle: nil).instantiateViewControllerWithIdentifier("P")
detailVC.self.navigationController?.pushViewController(newVC, animated: true)

Attempt 2:

let detailVC = self.splitViewController!.viewControllers[1]
let newVC = UIStoryboard(name: "D", bundle: nil).instantiateViewControllerWithIdentifier("P")
detailVC.performSegueWithIdentifier("navP", sender: self)

One other related question I had...if a user does many hops between several of the menu options, how can one "reset" the back button's history in the navigation bar to prevent a case where clicking back will cycle you through the same several views?

2

2 Answers

0
votes

You shouldn't be pushing the view controller or performing a segue but calling showViewController.

Do you definitely need to maintain the navigation bar or can you show different UINavigationBars (via showing your view controller embedded in an UINavigationViewController potentially)?

Alternatively just show a single view controller and use the logic you add in your view controller to change the content under the control of your master view controller.

0
votes

After some experimenting with the best approach I solved this. :) Solution below for all devices (iPhone/iPad).

Define extension for UISplitViewController:

Modified version based off https://stackoverflow.com/users/4418308/santiago-bendavid

extension UISplitViewController {
    func toggleMasterView() {
        if UIScreen.mainScreen().bounds.height > UIScreen.mainScreen().bounds.width {
            var nextDisplayMode: UISplitViewControllerDisplayMode
            switch(self.preferredDisplayMode){
            case .PrimaryHidden:
                nextDisplayMode = .AllVisible
            default:
                nextDisplayMode = .PrimaryHidden
            }
            UIView.animateWithDuration(0.2) { () -> Void in
                self.preferredDisplayMode = nextDisplayMode
            }
        } else {
            // do nothing
        }
    }
}

Code in master navigation controller's root view controller:

let newVC = UIStoryboard(name: "some_storyboard_id", bundle: nil).instantiateInitialViewController()
if self.splitViewController!.viewControllers.count == 2 {
    let detailVC = self.splitViewController!.viewControllers[self.splitViewController!.viewControllers.endIndex - 1]
    if detailVC.childViewControllers[detailVC.childViewControllers.count - 1].restorationIdentifier! != "some_id_here" { 
        detailVC.childViewControllers[0].navigationController?.pushViewController(newVC!, animated: true)
    }
    self.splitViewController!.toggleMasterView()                
    self.navigationController?.splitViewController!.preferredDisplayMode = .Automatic
} else {
    self.navigationController?.pushViewController(newVC!, animated: true)
}

This code works on regular iPhone (non-Plus) where the master view controller is the sole controller used for navigation. On iPads and iPhone 6/6s+ models (which behave same as an iPad) I check whether the current view is already present using the restoration ID property, and then present the new view if it's not the same as the one already rendered on screen and dismiss the master view controller if we're in portrait mode. If in landscape, we keep it on screen (default behavior).