4

I'm trying to display a ViewController as a popover on an iPhone. I have already been through several answers on SO and the rest of the web but none have worked so far. I wrote a simple app to test this.

ViewController.swift:

import UIKit

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(clicked(_:)))
    }

    func clicked(_ sender: Any) {
        let vc = UIViewController()
        vc.view.backgroundColor = UIColor.blue
        vc.preferredContentSize = CGSize(width: 200, height: 200)
        vc.modalPresentationStyle = .popover
        present(vc, animated: true, completion: nil)

        let ppc = vc.popoverPresentationController
        ppc?.permittedArrowDirections = .any
        ppc?.delegate = self
        ppc?.barButtonItem = navigationItem.rightBarButtonItem
    }

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

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

The storyboard has an empty ViewController embedded in a NavigationController.

Running this, I expected a popover view controller to show under the "done" button. Instead, the blue view controller is presented full screen.

Is there a way to change this behaviour?

mohak
  • 603
  • 1
  • 5
  • 11
  • Your have to set `sourceView` or `sourceRect` e.g `ppc?.sourceView = sender as! UIView` – Bilal May 18 '17 at 06:47
  • @Bilal the line `ppc?.barButtonItem = navigationItem.rightBarButtonItem` takes care of that – mohak May 18 '17 at 07:09

4 Answers4

11

You are connecting delegate after presenting view. How it will return .none from delegate and show as popover. Use this :-

    func clicked(_ sender: Any) {

        let vc = UIViewController()
        vc.view.backgroundColor = UIColor.blue
        vc.modalPresentationStyle = .popover

        vc.preferredContentSize = CGSize(width: 200, height: 200)

        let ppc = vc.popoverPresentationController
        ppc?.permittedArrowDirections = .any
        ppc?.delegate = self
        ppc?.barButtonItem = navigationItem.rightBarButtonItem
        ppc?.sourceView = sender

        present(vc, animated: true, completion: nil)

    }
Chanchal Warde
  • 983
  • 5
  • 17
4
import UIKit
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {

override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(clicked(_:)))
    }



func clicked(_ sender: Any) {
        let vc = UIViewController()
        vc.view.backgroundColor = UIColor.blue
        vc.preferredContentSize = CGSize(width: 200, height: 200)
        vc.modalPresentationStyle = .popover
        let ppc = vc.popoverPresentationController
        ppc?.permittedArrowDirections = .any
        ppc?.delegate = self
        ppc!.sourceView = sender as? UIView 
        ppc?.barButtonItem = navigationItem.rightBarButtonItem
        present(vc, animated: true, completion: nil)
    }

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


}
Himali Shah
  • 181
  • 1
  • 8
2

The solutions above no longer work in recent iOS versions 12 and above. To get it working again, override -modalPresentationStyle within the viewController to be presented as a popover and return UIModalPresentationPopover. Additionally provide a popoverPresentationController.delegate, implement adaptivePresentationStyleForPresentationController:traitCollection: and return UIModalPresentationNone.

@interface PopoverViewController : UIViewController
@end

@implementation PopoverViewController

- (UIModalPresentationStyle)modalPresentationStyle
{
    return UIModalPresentationPopover;
}

@end

@interface ViewController ()<UIPopoverPresentationControllerDelegate>
@end

@implementation ViewController

- (IBAction)openPopover:(id)sender
{
    UIViewController* testVC = [[PopoverViewController alloc] init];
    testVC.view.backgroundColor = UIColor.yellowColor;
    UIPopoverPresentationController* popPresenter = [testVC popoverPresentationController];
    popPresenter.permittedArrowDirections = UIPopoverArrowDirectionUp;
    popPresenter.delegate = self;
    popPresenter.sourceView = sender;
    popPresenter.sourceRect = [sender bounds];
    [self presentViewController:testVC animated:YES completion:^{}];
}

#pragma mark protocol (UIPopoverPresentationControllerDelegate)

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

@end
berbie
  • 978
  • 10
  • 13
-1

Add:

vc.popoverPresentationController?.delegate = self 

just before the line:

present(vc, animated: true, completion: nil)

enter image description here

bajocode
  • 260
  • 2
  • 10