简体   繁体   中英

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.

在此输入图像描述

在此输入图像描述

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.

在此输入图像描述

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

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

Storyboard: 在此输入图像描述

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.

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.

在此输入图像描述

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM