89

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

我遵循了文档,对于每个视图控制器,我设置了视图的 popover-context 大小,如下所示:

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

(每个控制器的尺寸不同)

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

但是,当我通过导航栏的“后退”按钮在视图堆栈中导航“后退”时,弹出框的大小不会改变——它仍然与到达的最深视图一样大。这对我来说似乎坏了;我希望弹出框在弹出视图堆栈时尊重设置的大小。

我错过了什么吗?

谢谢。

4

21 回答 21

95

我在同样的问题上苦苦挣扎。上述解决方案都不适合我,这就是为什么我决定做一些调查并找出它是如何工作的。

这是我发现的:

  • 当您contentSizeForViewInPopover在视图控制器中设置时,弹出框本身不会更改它 - 即使在导航到不同控制器时弹出框大小可能会发生变化。
  • 当导航到不同的控制器时弹出框的大小会发生变化,而返回时,弹出框的大小不会恢复
  • 在 viewWillAppear 中更改弹出框的大小会产生非常奇怪的动画(假设您在弹出框内使用 popController) - 我不推荐它
  • 对我来说,在控制器内部设置硬编码的大小根本不起作用——我的控制器有时必须很大有时很小——虽然控制器会告诉他们关于大小的想法

解决所有这些痛苦的方法如下:

currentSetSizeForPopover您必须在 viewDidAppear中重置大小。但是您必须小心,当您设置与已在字段中设置的大小相同的大小时,currentSetSizeForPopover弹出框不会更改大小。为此,您可以首先设置假尺寸(与之前设置的不同),然后设置正确的尺寸。即使您的控制器嵌套在导航控制器内,此解决方案也将起作用,并且当您在控制器之间导航时,弹出框将相应地更改其大小。

您可以使用以下辅助方法轻松地在 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所需的控制器中调用它。

于 2011-02-17T18:17:29.017 回答
19

这是我为 iOS 7 和 8 解决的方法:

在 iOS 8 中,iOS 默默地将你想要在 popover 中的视图包装到presentingViewController 视图控制器的presentedViewController 中。有一个 2014 年的 WWDC 视频解释了他们接触到的 popovercontroller 的新功能。

无论如何,对于出现在导航控制器堆栈上的所有视图控制器都需要自己的大小,这些视图控制器需要(在 iOS 8 下)调用此代码来动态设置首选内容大小:

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

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

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

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

类别.h:

#import <UIKit/UIKit.h>

@interface UITableViewController (PreferredContentSize)

- (void) setPopOverViewContentSize;

@end

类别.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
于 2014-11-17T02:59:45.247 回答
12

这是对krasnyk答案的改进。
您的解决方案很棒,但动画不流畅。
一点点改进可以提供漂亮的动画:

删除方法中的最后一行- (void) forcePopoverSize

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

将 [self forcePopoverSize] 放入- (void)viewWillAppear:(BOOL)animated方法中:

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

    [self forcePopoverSize];
}

最后 - 在- (void)viewDidAppear:(BOOL)animated方法中设置所需的大小:

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

    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
于 2011-10-13T12:27:12.947 回答
8

您需要在 中再次设置内容大小viewWillAppear。通过调用你设置popovercontroller大小的delagate方法。我也有同样的问题。但是当我添加这个时,问题就解决了。

还有一件事:如果您使用的是小于 5 的 beta 版本。那么弹出框更难管理。从 beta 版本 5 开始,它们似乎更加友好。最终版本出来了,这很好。;)

希望这可以帮助。

于 2010-05-02T13:09:58.743 回答
5

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

[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
于 2012-09-11T04:39:16.860 回答
3

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

-(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;
}
于 2010-06-01T01:46:41.580 回答
2

对于 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 版本兼容...

于 2014-10-29T08:50:52.510 回答
2
Well i worked out. Have a look.


Made a ViewController in StoryBoard. Associated with PopOverViewController class.


import UIKit

class PopOverViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.preferredContentSize = CGSizeMake(200, 200)

        self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss:")

    }

    func dismiss(sender: AnyObject) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}




See ViewController:


//
//  ViewController.swift
//  iOS8-PopOver
//
//  Created by Alvin George on 13.08.15.
//  Copyright (c) 2015 Fingent Technologies. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
{
    func showPopover(base: UIView)
    {
        if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("popover") as? PopOverViewController {


            let navController = UINavigationController(rootViewController: viewController)
            navController.modalPresentationStyle = .Popover

            if let pctrl = navController.popoverPresentationController {
                pctrl.delegate = self

                pctrl.sourceView = base
                pctrl.sourceRect = base.bounds

                self.presentViewController(navController, animated: true, completion: nil)
            }
        }
    }

    override func viewDidLoad(){
        super.viewDidLoad()
    }

    @IBAction func onShow(sender: UIButton)
    {
        self.showPopover(sender)
    }

    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
        return .None
    }
}


Note: The func showPopover(base: UIView) method should be placed before ViewDidLoad. Hope it helps !
于 2015-09-11T06:04:58.963 回答
1

对我来说,这个解决方案有效。这是我的视图控制器中的一种方法,它扩展了 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]; 
 }
于 2010-08-20T15:57:56.420 回答
1

如果您可以想象组装者,我认为这会稍微好一些:

- (void) forcePopoverSize {
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = CGSizeMake(0, 0);
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
于 2012-09-30T04:30:26.950 回答
1

接受的答案不适用于 iOS 8。我所做的是创建自己的子类以UINavigationController用于该弹出窗口并preferredContentSize以这种方式覆盖该方法:

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

此外,我决定设置一个 viewController(显示弹出框)作为前面提到的导航(在弹出框中)的委托,而不是调用forcePopoverSize(由@krasnyk 实现的方法),并在以下位置执行(强制方法的作用):viewDidAppear

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

传递的委托方法viewController。一件重要的事情是,如果你不需要动画是平滑的,那么forcePopoverSize在方法中做是很好的,如果是这样的话,那就把它留在.UINavigationControllerDelegateviewDidAppear

于 2014-10-22T12:01:32.107 回答
0

我遇到了同样的问题,但您不想在 viewWillAppear 或 viewWillDisappear 方法中设置 contentsize。

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 属性

于 2011-08-12T10:43:59.263 回答
0

通过将以下内容放入 viewdidappear 中,我很幸运:

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

尽管在您推动/弹出不同大小的弹出框的情况下,这可能不会很好地制作动画。但就我而言,效果很好!

于 2012-02-21T00:43:05.000 回答
0

您所要做的就是:

- 在 popOvers contentView 的 viewWillAppear 方法中,添加下面给出的代码片段。您必须在第一次加载 popOver 时指定它的大小。

CGSize size = CGSizeMake(width,height);
self.contentSizeForViewInPopover = size;
于 2012-04-06T18:48:12.207 回答
0

我有一个弹出框控制器的问题,它的 popoverContentSize = CGSizeMake(320, 600) 在开始时,但在通过它的 ContentViewController(一个 UINavigationController)导航时会变大。

导航控制器只是推送和弹出自定义 UITableViewControllers,所以在我的自定义表格视图控制器类的 viewDidLoad 中,我设置了 self.contentSizeForViewInPopover = CGSizeMake(320, 556)

少了 44 个像素是为了说明导航控制器的导航栏,现在我没有任何问题了。

于 2013-02-04T21:52:32.363 回答
0

把它放在你在弹出框内推送的所有视图控制器中

CGSize currentSetSizeForPopover = CGSizeMake(260, 390);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
                                      currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
于 2013-05-16T06:35:54.113 回答
0

面临同样的问题并通过在放置 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];
于 2013-09-26T14:46:06.420 回答
0

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

我实际上是在用这个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;

}

然后重复子视图...

于 2014-04-30T12:41:37.290 回答
0

这是 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];
}
于 2014-06-25T18:19:22.337 回答
0

@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 也有调整大小的问题:(。

于 2014-09-29T15:03:20.423 回答
0

您需要在以下位置设置preferredContentSizeNavigationController 的属性viewWillAppear

-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}
于 2015-05-21T08:28:29.493 回答