iOS Present View Controller Within Popup

14,355

Solution 1

This is only with Storyboard.

1) Create an UIViewController (blue) and ctrl + drag (mouse) from your UIBarButtonItem to the UIViewController and select "present as Popover" (like you did).

2) Click on the UIViewController (blue) and click on Editor->embed in->Navigation Controller (this will be trick to let the next controller stay in the popup)

3) Create a second UIViewController (green)

4) Create a UIButton in the first UIViewController (blue) and ctrl + drag from the button to the second UIViewController (green) and select "show"

At the end it should look like this in Storyboard:

enter image description here

And the result:

enter image description here

enter image description here

If you want the PopOver without the navigationBar you can use in the blue controller:

self.navigationController?.isNavigationBarHidden = true

and to go back from the green to the blue view you can use in the green controller:

@IBAction func backToBlueController(sender: UIButton) {
        self.navigationController?.popViewController(animated: true)
}

Additional:

If you don't want to use the popUp you could also change the segue kind from the barButtonItem to the navigationController to

Present Modally

and the presentation to something like

Form Sheet

in Storyboard.

enter image description here

At a glance, you should always use an UINavigationController to manage your navigation, even if you don't need the navigationBar, because the navigation controller provides you a navigation stack from where you can pop and push into it.

UINavigationController Reference

Solution 2

Create a IBAction of your UIBarButtonItem, and in action:

- (IBAction)popupAction:(UIBarButtonItem *)sender {
    UIViewController *vc = [[UIViewController alloc] init];  // I don't use segue
    vc.view.backgroundColor = [UIColor grayColor];
    vc.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController *popvc = vc.popoverPresentationController;
    popvc.delegate = self;
    popvc.permittedArrowDirections = UIPopoverArrowDirectionAny;
    popvc.barButtonItem = sender; // if UIBarButtonItem
    // if view
    // popvc.sourceView = sender;
    // popvc.sourceRect = sender.bounds;

    vc.preferredContentSize = CGSizeMake(200, 200);

    [self presentViewController:vc animated:YES completion:nil];
}

And the UIPopoverPresentationControllerDelegate:

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection{
    return UIModalPresentationNone;
}

- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController{
    return YES;
}

Swift:

@IBAction func popupAction(_ sender: UIBarButtonItem) {
    let vc = UIViewController.init()
    vc.view.backgroundColor = UIColor.gray
    vc.modalPresentationStyle = UIModalPresentationStyle.popover
    let popvc = vc.popoverPresentationController
    popvc?.delegate = self
    popvc?.permittedArrowDirections = UIPopoverArrowDirection.any
    popvc?.barButtonItem = sender
    vc.preferredContentSize = CGSize.init(width: 200, height: 200)

    self.present(vc, animated: true, completion: nil)
}

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
    return UIModalPresentationStyle.none
}

func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
    return true
}

This works on both iPad and iPhone.

Result:

Popover another viewController in a popover controller:

Share:
14,355
Charlie Fish
Author by

Charlie Fish

Software Engineer (iOS @ ForeFlight) 🖥📱, student pilot ✈️, HUGE Colorado Avalanche fan 🥅, entrepreneur (rrainn, Inc.) ⭐️ Contact me ✉️, About me 👨🏻‍💻, Terms 📝, Website 🌐

Updated on June 12, 2022

Comments

  • Charlie Fish
    Charlie Fish almost 2 years

    So I have my main view controller. That view controller has a bar button item with a storyboard segue with kind set as Present As Popover.

    This all works as expected. But when you tap another button within that popover view controller it presents the view full screen. I want it to display within the popover. Like push/display on top of the existing popover bounds.

    How can I achieve this?

    I only want this behavior on iPad. But I think it does that by default.

    Edit

    I'd prefer to do this all in the storyboard but am willing to do it with Swift code as well if that is what's required.