UIPopover arrow not repositioned correctly on rotation

This is one of those bug reports where a picture is worth a thousand words. The scenario is a basic collection view layout showing a grid of cells. Each cell contains a UILabel showing the cell row number for ease of reference:

Now suppose I want to show a popover view that is presented from one of the collection view cells. The code for that will be something like this:

[self.uylPopoverController presentPopoverFromRect:cell.frame

The appearance of the popover is shown below when it is presented from the cell at row 3:

This is fine until you rotate the device with the popover visible. By default the popover controller hides the popover and then shows it again when the rotation finishes. Unfortunately since my collection view layout repositions the cells the popover ends up pointing to the wrong cell. So for example here is the appearance with the device in portrait with the popover presented from cell 3:

Now if you rotate the device to landscape cell 3 moves to the top right hand corner and the popover ends up pointing to cell 4:

You can help the popover controller position the popover correctly by implementing the UIPopoverControllerDelegate method popoverController:willRepositionPopoverToRect:inView:. This method is new in iOS 7 and allows you to return a new position for the popover:

- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view
  if (self.uylPopoverController == popoverController)
    NSArray *selectedItems = self.collectionView.indexPathsForSelectedItems;
    NSIndexPath *itemPath = (NSIndexPath *)[selectedItems lastObject];
    if (itemPath)
      UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:itemPath];
      if (cell)
        CGRect requiredRect = cell.frame;
        *rect = requiredRect;

In this case I get the currently selected cell from the collection view controller and return the cell frame that at this point has already been moved into the new position. At first glance this seems to work if I happen to select the right cell. For example if I select cell 4:

On rotation the newly presented popover is correctly repositioned so that it still appears to have been presented from cell 4:

However if I select a cell where the relative position of the popover to the cell changes it does not work so well. For example, if I have a situation where the popover is presented from cell 3 in portrait mode it appears to the right of the cell with the arrow in the popover pointing to the left, back to cell 3:

When the device is rotated the popover is repositioned to follow the new position of cell 3. However since cell 3 is now much closer to the edge of the display the popover position relative to the cell must change. It is now presented to the left of cell 3 but the arrow which should be directed to the right where cell 3 is now positioned instead points to the left:

A close up screenshot of the popover makes the problem easier to see:

At time of writing I have not found a workaround for this problem. The bug report is 14995477 should you want to duplicate (also on Open Radar at rdar://14995477). An example Xcode project to reproduce the problem can be found in my GitHub CodeExamples repository. The project is named Collection.

Never miss a post!

iOS Size Classes Cheat Sheet

Subscribe and get my free iOS Size Classes Cheat Sheet

Success! Now check your email to confirm your subscription and download your free guide to iOS Size Classes.

There was an error submitting your subscription. Please try again.

Unsubscribe at any time.
No time to watch WWDC videos?

Sign up to get my iOS posts direct to your inbox and I will send you a free PDF of my iOS Size Classes Cheat Sheet.

OK! Check your inbox (or spam folder) for an email to confirm your details and download your free guide to iOS Size Classes.

There was an error submitting your subscription. Please try again.

Unsubscribe at any time.
Archives Categories