4
votes

While using a universal storyboard and adaptive segues, how can one implement a Present As Popover segue that will have a navigation bar (with a title and close button) only on iPhone when presented modally, and will not have a navigation controller on iPad when presented as a popover?

I believe the proper setup is to not include a nav controller in the storyboard, control-drag to the new view controller and select a Present As Popover segue. Then in prepareForSegue one will need to create the navigation controller and embed the destination controller in it, then add the title and buttons, but only if it will be presented modally. If that approach is correct, how can one do that in code?

2
No, that won't work. By the time prepareForSegue is called, the source and destination view controllers are already defined; you can't change the destination view controller by embedding it in a navigation controller.rdelmar

2 Answers

3
votes

Rdelmar is correct, you can't do this in prepareForSegue as the destination view controller is already set.

In iOS 7 and earlier you'll have to add that navigation controller to the storyboard and you could then have separate segues to the navigation controller and its root view. Then trigger the right segue on depending on whether you want the navigation controller (iPhone) or not (iPad).

In iOS 8 you can use the new UIAdaptivePresentationControllerDelegate protocol and then create a navigation controller on the fly where you need it:

func presentationController(controller: UIPresentationController!, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController! 
{
  let presented = controller.presentedViewController
  return UINavigationController(rootViewController: presented)
}
0
votes

To elaborate on this a little, if what you want is a popover on your iPad but a modal sheet with a close button on your iPhone then this is how you do it.

In Xcode 6.3 storyboard, you hook up a view controller and designate the segue as a "Present as Popover"

This code should go in the view controller that segues to the popover, not in the popover itself:

First you set up the popover delegate:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "myPopoverSegueName") {
        let vc = segue.destinationViewController
        vc.popoverPresentationController?.delegate = self
        return
    }
}

Then you add the delegate extension and create the navigation controller / close button on the fly:

extension myViewController: UIPopoverPresentationControllerDelegate {

    func presentationController(controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        let btnDone = UIBarButtonItem(title: "Done", style: .Done, target: self, action: "dismiss")
        let nav = UINavigationController(rootViewController: controller.presentedViewController)
        nav.topViewController.navigationItem.leftBarButtonItem = btnDone
        return nav
    }

}

Then you add your dismiss function and you should be good to go:

func dismiss() {
    self.dismissViewControllerAnimated(true, completion: nil)
}