Isuru
Isuru

Reputation: 31283

Segue from the MasterViewController in a SplitViewController to another View Controller

I have a SplitViewController with a UITableViewController as the masterViewController and a UIViewController as the detailViewController.

enter image description here

enter image description here

When the user taps a cell, I need to push to a new UITableViewController. So I added a segue from the cell to a UITableViewController. But what happens is the UITableViewController gets added to the masterViewController's stack.

enter image description here

How can I push to a whole new UITableViewController from the masterViewController?

Upvotes: 3

Views: 2599

Answers (2)

Isuru
Isuru

Reputation: 31283

I got it! First I should mention Michal's answer helped me to get an idea and point me in the right direction so thanks to him.

What I did was simple actually. Before I had a View Controller with a container view embedding the split view controller. I simply went ahead and embedded that view controller in a navigation controller.

enter image description here

Then I added the view controller I want to segue to in the storyboard but no segue attached to it. I'm doing it programatically in the masterViewController's didSelectRowAtIndexPath method.

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
if let rootVC = appDelegate.window?.rootViewController {
    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
    let mapVC = storyboard.instantiateViewControllerWithIdentifier("MapVC") as! UIViewController
    rootVC.showViewController(mapVC, sender: nil)
}

I get a reference to the rootViewController which is a navigation controller through the AppDelegate and I push the new view controller I want to it's stack.

That's it! Here's a demo project in case anyone's interested.

Upvotes: 3

Michal
Michal

Reputation: 15669

Here is a simple example how I approach such functionality (I created a new Master-Detail Application):

Storyboard: enter image description here

Notice that the root VC is now a UINavigationController. Therefore AppDelegate must be changed accordingly:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    let navCtr = self.window!.rootViewController as UINavigationController

    let splitViewController = navCtr.visibleViewController as UISplitViewController
    let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as UINavigationController
    navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
    splitViewController.delegate = self
    return true
}

And then finally in MasterViewController add this:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)

    if indexPath.row % 2 == 0 {
        self.performSegueWithIdentifier("showDetail", sender: nil)
    } else {
        let appDelegate  = UIApplication.sharedApplication().delegate as AppDelegate
        if let let rootCtr = appDelegate.window?.rootViewController {
            let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
            let newSplit = storyboard.instantiateViewControllerWithIdentifier("SplitVC") as UISplitViewController

            /// Because of Apple's "Split View Controllers cannot be pushed to a Navigation Controller" 
            let yetAnotherNavCtr = UINavigationController(rootViewController: newSplit)
            rootCtr.presentViewController(newSplit, animated: true, completion: nil)
        }
    }
}

Important notes:

  1. If you create new MasterDetail Application from the template, you have to disconnect the showDetail segue, because it is directly linked to the cell's selected callback. If you want to preserve that functionality as well, simply connect it again not from the cell itself, but from the whole VC. To be able to use it as in my funky didSelect... method that performs the showDetail segue on even rows.

  2. The Split View presentation will work only once - I haven't implemented the whole rootViewController replacement - the lldb will complain saying: Attempt to present UISplitViewController on UINavigationController whose view is not in the window hierarchy! if you'll try to do it for the second time. But that's really up to your requirements for how you want the app to behave.

  3. Name the SplitView Controller in Storyboard "SplitVC" (Storyboard ID) if you want to present the Split View Controller like I am doing in my code.

Upvotes: 3

Related Questions