how to center a popoverview in swift

I have the following code to show a popoverview (dialog) without an arrow, which works fine. The only problem is, that the dialog is shown in the top left (IPad). I would like to center the view on the screen.

What to change or add in my following code ? :

  • Create multi page PDF in objective-c
  • Replace blue dot in GMSMapView by an arrow - Swift
  • iOS 7, corrupt UINavigationBar when swiping back fast using the default interactivePopGestureRecognizer
  • Exception in iPad, UIImagePickerController must be presented via UIPopoverController
  • NSCachedURLResponse returns object, but UIWebView does not interprets content
  • Get UTC time and local time from NSDate object
  • func show_help(){
    
    
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let controller = storyboard.instantiateViewControllerWithIdentifier("Help") as! UIViewController
    
        controller.modalPresentationStyle = UIModalPresentationStyle.Popover
    
        let popoverPresentationController = controller.popoverPresentationController
    
        // result is an optional (but should not be nil if modalPresentationStyle is popover)
        if let _popoverPresentationController = popoverPresentationController {
    
            // set the view from which to pop up
            _popoverPresentationController.sourceView = self.view;
            _popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection.allZeros;
            // present (id iPhone it is a modal automatic full screen)
            self.presentViewController(controller, animated: true, completion: nil)
        }
    
    }
    

    Additional Infos

    enter image description here

    In my view, which is linked to my viewcontroller I set the preffered size like this:

    override func viewDidLoad() {
            let dialogheigth:CGFloat = self.view.frame.height * 0.5;
            let dialogwidth:CGFloat = self.view.frame.width * 0.5;
            self.preferredContentSize = CGSizeMake(dialogwidth,dialogheigth);
    }
    

    5 Solutions Collect From Internet About “how to center a popoverview in swift”

    You need to provide the source rect for the popover.

    From the apple documentation: the source rect is the rectangle in the specified view in which to anchor the popover. Use this property in conjunction with the sourceView property to specify the anchor location for the popover.

    In your case, under

    _popoverPresentationController.sourceView = self.view;
    

    add:

    _popoverPresentationController.sourceRect = CGRectMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds),0,0)
    

    It will do the trick!

    enter image description here

    Here’s an implementation using Swift 3

    let popover = storyboard?.instantiateViewController(withIdentifier: "popover") as! PopoverVC
    
        popover.modalPresentationStyle = UIModalPresentationStyle.popover
        popover.popoverPresentationController?.backgroundColor = UIColor.green
        popover.popoverPresentationController?.delegate = self
    
        popover.popoverPresentationController?.sourceView = self.view
        popover.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
    
        popover.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
    
        self.present(popover, animated: true)
    

    Based on Istvan’s
    answer

    In iOS8, you don’t need to use self.view.frame to calculate width and height.

    You can the dialog height and width using the following way:

    override func viewDidLoad() {
         var frameSize: CGPoint = CGPointMake(UIScreen.mainScreen().bounds.size.width*0.5, UIScreen.mainScreen().bounds.size.height*0.5)
         self.preferredContentSize = CGSizeMake(frameSize.x,frameSize.y);
    }
    

    Edited:

    You can also set contentSizeForViewInPopover as below too:

    self.contentSizeForViewInPopover = CGSizeMake(320.0, 360.0)
    

    Let me know this helps or not?

    Another way for Swift 3 (Xcode 8, iOS 9) is this:

    Called from somewhere:

    self.performSegue(withIdentifier: "showPopupSegue", sender: yourButton)
    

    Function that gets called before segue gets fired:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let popoverPresentationController = segue.destination.popoverPresentationController {
            let controller = popoverPresentationController
            controller.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
            controller.sourceView = self.view
            controller.sourceRect = CGRect(x: UIScreen.main.bounds.width * 0.5 - 200, y: UIScreen.main.bounds.height * 0.5 - 100, width: 400, height: 200)
            segue.destination.preferredContentSize=CGSize(width: 400, height: 200)
        }
    }
    

    Remember to set the storyboard segue’s Kind attribute to “Present as Popover” and Anchor attribute to any view in your previous view controller.

    Basically consist of three steps (iOS 8):

    1.- Present the view:

    Let’s say, you want to show a custom view to ask for a Review to the user.. here the function loadNibForRate() returns an instance of RateDialog loaded from its nib, but you can use here any way you desire to locate your UIViewController

    private static func presentCustomDialog(parent: RateDialogParent) -> Bool {
        /// Loads the rateDialog from its xib, handled this way for further customization if desired
          if let rateDialog = loadNibForRate() {
            rateDialog.modalPresentationStyle = UIModalPresentationStyle.Popover
            rateDialog.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
            let x = parent.view.center
    
            let sourceRectX : CGFloat
            //Here we check for the orientation of the device, just to know if we are on an iPad
            let maximumDim = max(UIScreen.mainScreen().bounds.height, UIScreen.mainScreen().bounds.width)
            if maximumDim == 1024 { //iPad
                sourceRectX = x.x
            }else {
                sourceRectX = 0
            }
    
            rateDialog.popoverPresentationController?.sourceView = parent.view
            rateDialog.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.allZeros
            rateDialog.popoverPresentationController?.sourceRect = CGRectMake(sourceRectX, x.y, 0, 0)
            rateDialog.popoverPresentationController?.popoverLayoutMargins = UIEdgeInsetsMake(0, 0, 0, 0)
            rateDialog.popoverPresentationController?.delegate = parent
    
            rateDialogParent = parent
    
            callFunctionAsync() {
                parent.presentViewController(rateDialog, animated: true, completion: nil)
            }
            return true
        }
        return false
    }
    

    2.- If we rotate our device, then the popover will not know where to reposition itself, unless we have this on the parent
    RateDialogParent

    public class RateDialogParent: UIViewController, UIPopoverPresentationControllerDelegate {
    /**
    This function guarantees that the RateDialog is alwas centered at parent, it locates the RateDialog's view by searching for its tag (-555)
     */
     public func popoverPresentationController(popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverToRect rect: UnsafeMutablePointer<CGRect>, inView view: AutoreleasingUnsafeMutablePointer<UIView?>) {
        if popoverPresentationController.presentedViewController.view.tag == RateDialog.thisViewTag {
            let x = popoverPresentationController.presentingViewController.view.center
            let newRect = CGRectMake(x.x, x.y, 0, 0)
            rect.initialize(newRect)
        }
     }
    }
    

    3.- Your RateDialog should have a tag setted, this is just to avoid relocating unwanted popovers if there is more that one presented
    from your RateDialogParent

    class RateDialog: UIViewController {
     @IBOutlet weak var reviewTitle: UILabel!
     @IBOutlet weak var reviewMessage : UILabel!
     @IBOutlet weak var cancelButtonTitle: UIButton!
     @IBOutlet weak var remindButtonTitle : UIButton!
     @IBOutlet weak var rateButtonTitle : UIButton!
    
        /// For being able to locate this view
     static let thisViewTag = -555
    
     override func viewDidLoad() {
        super.viewDidLoad()
        //sets the tag to identify this view
        self.view.tag = RateDialog.thisViewTag
     }
    }