37
votes

I'm having trouble changing the size of my popover presentation. Here is what I have so far

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) // func for popover
{
    if segue.identifier == "popoverView"
    {
        let vc = segue.destinationViewController

        let controller = vc.popoverPresentationController

        if controller != nil
        {
            controller?.delegate = self
            controller?.sourceView = self.view
            controller?.sourceRect = CGRect(x:CGRectGetMidX(self.view.bounds), y: CGRectGetMidY(self.view.bounds),width: 315,height: 230)
            controller?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
        }
    }
}

So far all this does is center the popover and remove the arrow, which is good. but it doesn't resize the container. any help would be greatly appreciated. thank you.

when I use preferredContentSize I get the error "Cannot assign to property: 'preferredContentSize' is immutable"

6
Why don't you present as a modal form sheet instead of trying to use a popover in a way that isn't intended?Wain
sorry, I didn't specify. This will be for iPhone. according to apple, you can not re-size a modal form sheet on iPhone but you can on an iPad. Unless I read that wrong. also, I have tried several different ways to re-size the popover but nothing seems to be working. I am sure there is a simple fix for the code I have provided. I just haven't found it yet.icestorm0806

6 Answers

66
votes

Set the preferred content size on the view controller being presented not the popoverPresentationController

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) // func for popover
    {
        if segue.identifier == "popoverView"
        {
            let vc = segue.destinationViewController

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

            let controller = vc.popoverPresentationController

            controller?.delegate = self
            //you could set the following in your storyboard
            controller?.sourceView = self.view
            controller?.sourceRect = CGRect(x:CGRectGetMidX(self.view.bounds), y: CGRectGetMidY(self.view.bounds),width: 315,height: 230)
            controller?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)

        }
    }
35
votes

I fixed it via storyboard : Click on your controller Click on Attribute inspector ViewController> Check Use Preferred Explicit size and input values. enter image description here

8
votes

Using Auto Layout

It may be worth mentioning that you can use layout constraints instead of setting preferredContentSize to specific values. To do so,

  1. Add this to your view controller:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.preferredContentSize = self.view.systemLayoutSizeFitting(
            UIView.layoutFittingCompressedSize
        )
    }
    
  2. Ensure that you have constraints from your popover view to the controller's root view. These can be low priority, space >= 0 constraints.

4
votes

Above answers are correct which states about using the preferredContentSize, but the most important thing is to implement the protocol UIPopoverPresentationControllerDelegate and implement the below method otherwise it will not change the content size as expected.

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

Similar to Xeieshan's answer above, I set this via the storyboard.
Except that "Presentation" also needed to be to "Form Sheet".

enter image description here

2
votes

I'm not using storyboards. I just present a UINavigationController in the popover:

    self.present(popoverNavigationController!, animated: true) {}

The way to resize the popover size when a new view controller is pushed, it is just change the preferredContentSize before pushing it. For example:

    let newViewController = NewViewController()
    popoverNavigationController!.preferredContentSize = CGSize(width: 348, height: 400)
    popoverNavigationController!.pushViewController(newViewController, animated: true)

The problem is when we try to resize the popover when we pop a view controller.

If you use viewWillDisappear of the current view controller to change the preferredContentSize of the popover, the popover will resize but after the view controller is popped. That means that the animation has a delay.

You have to change the preferredContentSize before executing popViewController. That's mean you have to create a custom back button in the navigation bar like it is explained here. This is the implementation updated for Swift 4:

        self.navigationItem.hidesBackButton = true
        let newBackButton = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(CurrentViewController.backButtonTapped(sender:)))       
        self.navigationItem.leftBarButtonItem = newBackButton

And run the next code when the new Back button is pressed:

   @objc func backButtonTapped(sender: UIBarButtonItem) {

        self.navigationController?.preferredContentSize = CGSize(width: 348, height: 200)

        self.navigationController?.popViewController(animated: true)
   }

Basically, the preferredContentSize has to be changed before pushing and popping the view controller.