Popover with embedded navigation controller doesn't respect size on back nav Popover with embedded navigation controller doesn't respect size on back nav ios ios

Popover with embedded navigation controller doesn't respect size on back nav


I was struggling with the same issue. None of the above solutions worked for me pretty nicely, that is why I decided to do a little investigation and find out how this works.

This is what I discovered:

  • When you set the contentSizeForViewInPopover in your view controller it won't be changed by the popover itself - even though popover size may change while navigating to different controller.
  • When the size of the popover will change while navigating to different controller, while going back, the size of the popover does not restore
  • Changing size of the popover in viewWillAppear gives very strange animation (when let's say you popController inside the popover) - I'd not recommend it
  • For me setting the hardcoded size inside the controller would not work at all - my controllers have to be sometimes big sometimes small - controller that will present them have the idea about the size though

A solution for all that pain is as follows:

You have to reset the size of currentSetSizeForPopover in viewDidAppear. But you have to be careful, when you will set the same size as was already set in field currentSetSizeForPopover then the popover will not change the size. For this to happen, you can firstly set the fake size (which will be different than one which was set before) followed by setting the proper size. This solution will work even if your controller is nested inside the navigation controller and popover will change its size accordingly when you will navigate back between the controllers.

You could easily create category on UIViewController with the following helper method that would do the trick with setting the size:

- (void) forcePopoverSize {    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);    self.contentSizeForViewInPopover = fakeMomentarySize;    self.contentSizeForViewInPopover = currentSetSizeForPopover;}

Then just invoke it in -viewDidAppear of desired controller.


Here's how I solved it for iOS 7 and 8:

In iOS 8, iOS is silently wrapping the view you want in the popover into the presentedViewController of the presentingViewController view controller. There's a 2014 WWDC video explaining what's new with the popovercontroller where they touch on this.

Anyways, for view controllers presented on the navigation controller stack that all want their own sizing, these view controllers need (under iOS 8) to call this code to dynamically set the preferredContentSize:

self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);

Replace heightOfTable with your computed table or view height.

In order to avoid a lot of duplicate code and to create a common iOS 7 and iOS 8 solution, I created a category on UITableViewController to perform this work when viewDidAppear is called in my tableviews:

- (void)viewDidAppear:(BOOL)animated {    [super viewDidAppear:animated];    [self setPopOverViewContentSize];}

Category.h:

#import <UIKit/UIKit.h>@interface UITableViewController (PreferredContentSize)- (void) setPopOverViewContentSize;@end

Category.m:

#import "Category.h"@implementation UITableViewController (PreferredContentSize)- (void) setPopOverViewContentSize{    [self.tableView layoutIfNeeded];    int heightOfTable = [self.tableView contentSize].height;    if (heightOfTable > 600)        heightOfTable = 600;    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0)            self.preferredContentSize=CGSizeMake(320, heightOfTable);        else            self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);    }}@end


This is an improvement on krasnyk's answer.
Your solution is great, but it isn't smoothly animated.
A little improvement gives nice animation:

Remove last line in the - (void) forcePopoverSize method:

- (void) forcePopoverSize {    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);    self.contentSizeForViewInPopover = fakeMomentarySize;}

Put [self forcePopoverSize] in - (void)viewWillAppear:(BOOL)animated method:

- (void)viewWillAppear:(BOOL)animated{    [super viewWillAppear:animated];    [self forcePopoverSize];}

And finally - set desired size in - (void)viewDidAppear:(BOOL)animated method:

- (void)viewDidAppear:(BOOL)animated{    [super viewDidAppear:animated];    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;    self.contentSizeForViewInPopover = currentSetSizeForPopover;}