I've noticed in a project that the positioning of a popover over a right bar button item seems to be off to the right for some reason. I've tried instead using a UIButton for the custom view, then presenting the popover from that button, but popover seems to ignore the showFromRect if I actually provide it with the 'centered' value.
The code behind this is quite simple:
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"share"] style:UIBarButtonItemStylePlain target:self action:@selector(shareTap:)];
self.navigationItem.rightBarButtonItem = button;
}
- (void)shareTap:(UIBarButtonItem *)button {
self.popover = [[UIPopoverController alloc] initWithContentViewController:[[UIViewController alloc] init]];
[self.popover presentPopoverFromBarButtonItem:button permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Now, if I switch to using the internal button, as mentioned, I see similar behavior (note color change so image shows up).
The code for this is still fairly simple:
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *innerButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 22, 22)];
[innerButton setImage:[UIImage imageNamed:@"share"] forState:UIControlStateNormal];
[innerButton addTarget:self action:@selector(shareTap:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:innerButton];;
}
- (void)shareTap:(UIButton *)button {
self.popover = [[UIPopoverController alloc] initWithContentViewController:[[UIViewController alloc] init]];
// CGRect bottomCenter = CGRectMake(button.frame.size.width / 2, button.frame.size.height, 1, 1);
CGRect bottomCenter = CGRectMake(2, button.frame.size.height, 1, 1);
[self.popover presentPopoverFromRect:bottomCenter inView:button permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Note here that instead of using the actual center, I've used the arbitrary value, 2. If I use 1 or 0, the popover becomes left-aligned. Anything greater than one is right aligned again.
I searched around a bit looking for a similar question, but I can't seem to find anyone with the same problem. Any idea around what causes this or how to avoid it would be greatly appreciated. The only thing I've been able to guess at is that due to its proximity to the edge, Apple does some positioning voodoo to force it to be where they want it. The problem is that top-right corner button seems like a pretty standard drop down position.
Edit: I've confirmed this same behavior occurs with a long-press on the "New Message" icon in the native Mail app.
Edit 2: I was able to confirm with Apple that this is an issue. In one of the more recent versions (I can't remember which, one of the 9s I think), they made it so you can manually set this. The default behavior is still wrong I believe (I haven't tried this for a while), but you can use the CGRect offset method to make it work correctly, should you be so inclined.
Here's one way to do this: Instead of using a UIBarButtonSystemItem
, use a UIBarButtonItem
with a custom view. Just drag a UIButton
into the UINavigationBar
to get a UIBarButtonItem
with an embedded UIButton
, which shows up as the UIBarButtonItem
's customView.
@IBAction func didTapActionButton(_ sender: Any) {
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "myPopover") {
vc.modalPresentationStyle = .popover
guard let innerView = actionButton.customView else {
// Unexpected missing custom view
return
}
vc.popoverPresentationController?.sourceView = navigationController?.navigationBar
vc.popoverPresentationController?.sourceRect = innerView.frame
self.present(vc, 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