I've written code to present a popover from a UICollectionView cell if the cell is selected but is unavailable for whatever reason. It works fine, except the content is never correctly positioned within the popup bubble. Note from the two examples shown, that the content is always shifted toward the caret by about half the thickness of the caret.
It's clear that the size is being computed properly, but it just seems like the popover controller is simply calculating the position of the popupView incorrectly. Since the direction of shift is out of my control, I can't just shift everything over by a few pixels as a workaround.
The storyboard simply has a popupView with constraints to center it horizontally and vertically within the scene view:
And here's my code... Note I've turned on the border around the view just to accentuate the shift.
// Inside collectionView:didSelectItemAtIndexPath:
UIStoryboard* mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
MenuUnavailableViewController* muc = [mainStoryboard instantiateViewControllerWithIdentifier:@"MenuOptionUnavailable"];
muc.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:muc animated:NO completion:nil];
MenuCollectionViewCell* menuCell = (MenuCollectionViewCell*) [menuCollection cellForItemAtIndexPath:indexPath];
muc.popoverPresentationController.sourceView = menuCollection;
muc.popoverPresentationController.sourceRect = menuCell.frame;
muc.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
@implementation MenuUnavailableViewController
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.view layoutSubviews];
self.preferredContentSize = self.popupView.bounds.size;
self.popupView.layer.borderColor = [UIColor blackColor].CGColor;
self.popupView.layer.borderWidth = 2;
self.popupView.layer.cornerRadius = 12;
}
I've been doing popovers successfully using this formula for quite a while, and then one day some iOS or Xcode update silently broke the positioning (not sure, but I think it was around iOS 13 or 14). Anyone have an idea what I'm doing wrong? I've been looking for a complete example implementing popovers under a recent iOS version, but can't find one anywhere.



Not sure what might have changed, or when... and, maybe you were "getting lucky" with your layouts so you didn't notice it... but...
We want to set the
.preferredContentSizebased on the size of the controller's view - not yourpopupViewsubview.Also, we want to make sure the content is constrained to the safe-area.
So, if I setup a
MenuUnavailableViewControllerlike this:With "Unavailable" and "Reason:" labels Content Hugging and Compression Resistance Priorities all set to
Required...Unavailable Lbllabel will determine the WidthIn the calling controller, set string properties for the labels.
Then,
MenuUnavailableViewControllerclass looks like this:No need to do anything in
viewWillAppear.Here's how it looks (cycling through 3 sets of strings):
and if we clear the colors and border:
and, just to show it works for different "arrow" directions: