从 Split ViewController 中的 Master ViewController 转到另一个 View Controller

Segue from the MasterViewController in a SplitViewController to another View Controller

我有一个 SplitViewController,其中 UITableViewController 作为 masterViewController,UIViewController 作为 detailViewController。

当用户点击一个单元格时,我需要推送到一个新的 UITableViewController。所以我从单元格添加了一个 segue 到 UITableViewController。但是发生的是 UITableViewController 被添加到 masterViewController 的堆栈中。

如何从 masterViewController 推送到一个全新的 UITableViewController

这里是一个简单的例子,我是如何处理这些功能的(我创建了一个新的 Master-Detail Application):

故事板:

请注意,根 VC 现在是 UINavigationController。因此 AppDelegate 必须相应地更改:

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
}

最后在 MasterViewController 中添加:

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)
        }
    }
}

重要提示:

  1. 如果您从模板创建新的 MasterDetail 应用程序,您必须断开 showDetail segue,因为它直接链接到单元格的 selected 回调。如果您还想保留该功能,只需再次连接它,而不是从单元格本身,而是从整个 VC。为了能够像在我时髦的 didSelect... 方法中一样使用它,该方法在偶数行上执行 showDetail segue。

  2. Split View 演示文稿只能工作一次 - 我还没有实现整个 rootViewController 替换 - lldb 会抱怨说:Attempt to present UISplitViewController on UINavigationController whose view is not in the window hierarchy!如果你第二次尝试这样做。但这实际上取决于您对应用程序行为方式的要求。

  3. Storyboard "SplitVC"(故事板 ID)中命名 SplitView 控制器,如果你想像我在我的代码中那样呈现 Split View 控制器。

我明白了!首先,我应该提到 Michal 的回答帮助我有了一个想法并指出了正确的方向,所以感谢他。

我做的其实很简单。在我有一个带有容器视图的视图控制器之前,容器视图嵌入了拆分视图控制器。我只是继续将那个视图控制器嵌入到导航控制器中。

然后我在情节提要中添加了我想继续使用的视图控制器,但没有附加到它。我在 masterViewController 的 didSelectRowAtIndexPath 方法中以编程方式进行。

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)
}

我通过 AppDelegate 获得了对导航控制器 rootViewController 的引用,并将我想要的新视图控制器推送到它的堆栈。

就是这样!如果有人感兴趣,这里有一个演示 project