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)
}
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.
There is an issue in iOS 9. Setting the anchor in a storyboard:
...results in the arrow not being centered on the anchor:
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
}
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With