ios - 带有嵌入式导航控制器的弹出式窗口不会考虑后导航栏的大小




uiviewcontroller uinavigationcontroller (14)

我有一个UIPopoverController托管一个UINavigationController,它包含一个小的层次结构的视图控制器。

我遵循文档和每个视图控制器,我设置视图的弹出窗口大小如下所示:

[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];

(每个控制器的大小不同)

当我在层次结构中向前导航时,这会按预期工作 - 弹出窗口会自动为尺寸更改设置动画,以对应于推送的控制器。

但是,当我通过导航栏的“后退”按钮导航“后退”视图堆栈时,弹出窗口不会更改大小 - 它保持与最深处视图一样大。 这似乎打破了我; 我希望弹出窗口能够尊重在视图堆栈中弹出时设置的大小。

我错过了什么吗?

谢谢。


@krasnyk解决方案在以前的iOS版本中运行良好,但不适用于iOS8。 以下解决方案适用于我。

    - (void) forcePopoverSize {
        CGSize currentSetSizeForPopover = self.preferredContentSize;
       //Yes, there are coupling. We need to access the popovercontroller. In my case, the popover controller is a weak property in the app's rootVC.
        id mainVC = [MyAppDelegate appDelegate].myRootVC;
        if ([mainVC valueForKey:@"_myPopoverController"]) {
            UIPopoverController *popover = [mainVC valueForKey:@"_myPopoverController"];
            [popover setPopoverContentSize:currentSetSizeForPopover animated:YES];
        }
    }

这不是最好的解决方案,但它有效。

新的UIPopoverPresentationController也有调整大小问题:(。


下面是我为iOS 7和8解决它的方法:

在iOS 8中,iOS默默地将您想要的视图封装到presentationViewController视图控制器的renderedViewController中。 有一个2014年的WWDC视频解释了他们在这方面涉及的popovercontroller的新功能。

无论如何,对于导航控制器堆栈中呈现的视图控制器,都需要它们自己的大小,这些视图控制器需要(在iOS 8下)调用此代码来动态设置preferredContentSize:

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

将heightOfTable替换为您的计算表或视图高度。

为了避免大量重复的代码并创建一个通用的iOS 7和iOS 8解决方案,我在UITableViewController上创建了一个类别,以便在我的tableviews中调用viewDidAppear时执行此项工作:

- (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

在导航控制器中使用的所有视图控制器的-(void)viewDidLoad中,添加:

[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];

好的,我在同一个问题上挣扎。 上述解决方案都不能很好地为我工作,这就是为什么我决定做一个小调查,并找出它是如何工作的。 这就是我发现的: - 当你在你的视图控制器中设置contentSizeForViewInPopover ,它不会被弹窗本身改变 - 即使导航到不同控制器时弹窗大小可能会改变。 - 当导航到不同的控制器时,弹出窗口的大小会改变,但返回时,弹出窗口的大小不会恢复 - 改变viewWillAppear中弹出窗口的大小会给出非常奇怪的动画(当我们说弹出窗口中的popController时)我不会推荐它 - 对我来说,在控制器内部设置硬编码大小根本不起作用 - 我的控制器有时会很大,有时很小 - 控制器会给他们提供关于大小的想法

所有这些痛苦的解决方案如下:您必须在viewDidAppear中重置currentSetSizeForPopover的大小。 但是你必须要小心,当你设置和currentSetSizeForPopover设置的大小相同的大小时,popover不会改变大小。 要发生这种情况,您可以首先设置假尺寸(与之前设置的尺寸不同),然后设置合适的尺寸。 即使您的控制器嵌套在导航控制器中,此解决方案也可以工作,并且当您将在控制器之间导航时,弹出窗口会相应地更改其大小。

您可以使用以下帮助器方法在UIViewController上轻松创建类别,该方法可以通过设置尺寸来实现:


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

然后,只需在所需控制器的-viewDidAppear中调用它。


对于iOS 8,以下工作:

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

顺便说一句,我认为,这应该与以前的iOS版本兼容...


对我来说,这个解决方案有效 这是我的视图控制器中的一种方法,它扩展了UITableViewController并且是UINavigationController的根控制器。

-(void)viewDidAppear:(BOOL)animated {
     [super viewDidAppear:animated];
     self.contentSizeForViewInPopover = self.tableView.bounds.size;
}

不要忘记设置视图控制器的内容大小,你会推入导航堆栈

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
    dc = [[DetailsController alloc] initWithBookmark:[[bookmarksArray objectAtIndex:indexPath.row] retain] bookmarkIsNew:NO];
    dc.detailsDelegate = self;
    dc.contentSizeForViewInPopover = self.contentSizeForViewInPopover;
    [self.navigationController pushViewController:dc animated:YES]; 
 }

您需要在viewWillAppear设置NavigationController的preferredContentSize属性:

-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}

我只想提供另一种解决方案,因为这些解决方案都不适合我...

我实际上使用它与此https://github.com/nicolaschengdev/WYPopoverController

当你第一次打电话弹出使用这个。

if ([sortTVC respondsToSelector:@selector(setPreferredContentSize:)]) {
   sortTVC.preferredContentSize = CGSizeMake(popoverContentSortWidth,
        popoverContentSortHeight);
}
else 
{
   sortTVC.contentSizeForViewInPopover = CGSizeMake(popoverContentSortWidth, 
        popoverContentSortHeight);
}

然后在该弹出窗口中使用这个。

-(void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:YES];

  if ([self respondsToSelector:@selector(setPreferredContentSize:)]) {
    self.preferredContentSize = CGSizeMake(popoverContentMainWidth, 
        popoverContentMainheight);
  }
  else 
  {
    self.contentSizeForViewInPopover = CGSizeMake(popoverContentMainWidth, 
        popoverContentMainheight);
  }
}

-(void)viewDidDisappear:(BOOL)animated {
 [super viewDidDisappear:YES];

self.contentSizeForViewInPopover = CGSizeZero;

}

然后重复儿童视图...


我重置viewWillDisappear中的大小:(BOOL)正在从以下位置导航回来的视图控制器的动画方法:

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    CGSize contentSize = [self contentSizeForViewInPopover];
    contentSize.height = 0.0;
    self.contentSizeForViewInPopover = contentSize;
}

然后,当导航回到的视图出现时,我会适当地重新设置大小:

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    CGSize contentSize;
    contentSize.width = self.contentSizeForViewInPopover.width;
    contentSize.height = [[self.fetchedResultsController fetchedObjects] count] *  self.tableView.rowHeight;
    self.contentSizeForViewInPopover = contentSize;
}

我面临同样的问题,但您不想在viewWillAppear或viewWillDisappear方法中设置内容。

AirPrintController *airPrintController = [[AirPrintController alloc] initWithNibName:@"AirPrintController" bundle:nil];
airPrintController.view.frame = [self.view frame];
airPrintController.contentSizeForViewInPopover = self.contentSizeForViewInPopover;
[self.navigationController pushViewController:airPrintController animated:YES];
[airPrintController release];

在将该控制器推送到navigationController之前,为该控制器设置contentSizeForViewInPopover属性


接受的答案在iOS 8中工作不正常。我所做的是创建我自己的UINavigationController的子类以用于该弹出窗口,并以此方式覆盖方法preferredContentSize

- (CGSize)preferredContentSize {
    return [[self.viewControllers lastObject] preferredContentSize];
}

此外,我没有在viewDidAppear中调用forcePopoverSize (由@krasnyk实现的方法),而是决定将一个viewController(它显示弹出窗口)设置为前面提到的导航(在弹出窗口中)和do(强制方法的作用)的代理:

-(void)navigationController:(UINavigationController *)navigationController
      didShowViewController:(UIViewController *)viewController 
                   animated:(BOOL)animated  

传递viewController委托方法。 一个重要的事情,在UINavigationControllerDelegate方法中执行forcePopoverSize是没有问题的,如果你不需要那个动画是平滑的,如果是的话就把它留在viewDidAppear


这是iOS7中正确的方法,在导航堆栈中的每个视图控制器中设置viewDidLoad中的首选内容大小(仅执行一次)。 然后在viewWillAppear中获取对popover控制器的引用,并在那里更新contentSize。

-(void)viewDidLoad:(BOOL)animated
{
    ...

    self.popoverSize = CGSizeMake(420, height);
    [self setPreferredContentSize:self.popoverSize];
}

-(void)viewWillAppear:(BOOL)animated
{
    ...

    UIPopoverController *popoverControllerReference = ***GET REFERENCE TO IT FROM SOMEWHERE***;
    [popoverControllerReference setPopoverContentSize:self.popoverSize];
}

通过在viewdidar中显示以下内容,我有幸运:

[self.popoverController setPopoverContentSize:self.contentSizeForViewInPopover animated:NO];

虽然在推动/弹出不同大小的弹出窗口时,这可能不会很好地动画。 但在我的情况下,完美的作品!


面对相同的问题,并通过在放置UIPopoverController的init之前将内容视图大小设置为导航控制器和视图控制器来修复它。

     CGSize size = CGSizeMake(320.0, _options.count * 44.0);
    [self setContentSizeForViewInPopover:size];
    [self.view setFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
    [navi setContentSizeForViewInPopover:size];

    _popoverController = [[UIPopoverController alloc] initWithContentViewController:navi];




uipopovercontroller