Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Popover doesn't center on button

I am trying to center a popover on a button. I can't seem to figure out where I might be going wrong. Instead of the arrow being in the middle of the button, it is off center by half the width of the screen.

 @IBAction func buttonClicked(sender: AnyObject){
    var popoverViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ServiceOptions") as! ServiceOptionsPopover
    popoverViewController.delegate = self
    popoverViewController.modalPresentationStyle = .Popover
    popoverViewController.preferredContentSize   = CGSizeMake(300, 300)

    let popoverPresentationViewController = popoverViewController.popoverPresentationController

    popoverPresentationViewController?.permittedArrowDirections = .Up
    popoverPresentationViewController?.delegate = self
    popoverPresentationViewController?.sourceView = sender as! UIButton
    popoverPresentationViewController?.sourceRect = sender.frame

    presentViewController(popoverViewController, animated: true, completion: nil)
}
like image 712
user3642915 Avatar asked May 05 '15 22:05

user3642915


3 Answers

The problem is the elementary one of confusing frame and bounds:

popoverPresentationViewController?.sourceView = sender as! UIButton
popoverPresentationViewController?.sourceRect = sender.frame

No! You mean bounds:

popoverPresentationViewController?.sourceView = sender as! UIButton
popoverPresentationViewController?.sourceRect = (sender as! UIButton).bounds

The reason is that the sourceRect is given in the coordinate space of the sourceView - that is, if you want it to be the view's rect, it's the bounds of that view.

like image 143
matt Avatar answered Nov 17 '22 22:11

matt


There is an issue in iOS 9. Setting the anchor in a storyboard:

enter image description here

...results in the arrow not being centered on the anchor:

enter image description here

To resolve, add this to prepareForSegue:sender::

// Fixes popover anchor centering issue in iOS 9
if let popoverPresentationController = segue.destinationViewController.popoverPresentationController, sourceView = sender as? UIView {
  popoverPresentationController.sourceRect = sourceView.bounds
}

enter image description here

like image 39
Scott Gardner Avatar answered Nov 17 '22 23:11

Scott Gardner


Here is the right way:

@IBAction func buttonClicked(sender: UIButton){
    var popoverViewController = UIViewController()
    popoverViewController.view.frame = CGRectMake(0,0, 300, 300)
    popoverViewController.view.backgroundColor = UIColor.redColor()
    popoverViewController.modalPresentationStyle = .Popover
    popoverViewController.preferredContentSize   = CGSizeMake(300, 300)

    let popoverPresentationViewController = popoverViewController.popoverPresentationController

    popoverPresentationViewController?.permittedArrowDirections = .Up
    popoverPresentationViewController?.sourceView = sender
    popoverPresentationViewController?.sourceRect = CGRectMake(0, 0, sender.bounds.width,sender.bounds.height) // see this line of code

    presentViewController(popoverViewController, animated: true, completion: nil)
}
like image 44
Vijay Masiwal Avatar answered Nov 17 '22 22:11

Vijay Masiwal