如何动态更改UIPopoverController的contentSize?

26

我有一个包含 UITableViewUIViewController

这个 UIViewControllerUIPopoverController 中显示。

现在问题是,tableView 中项的数量不是恒定的,我想让弹出窗口的大小(也就是 popoverContentSize),根据 tableView 中项目的数量进行调整。

一开始我天真地认为,在加载了所有项目的 tableView 后,在 viewDidLoad 中设置 contentSizeForViewInPopover 就可以了。

但事实并非如此。

所以简而言之,我的问题是:在展示后,我如何直接从 contentViewController 更改 popoverContentSize

附录: enter image description here

8个回答

47

我可能回答得很晚,但对于iOS 7的新用户,请在您的UIPopoverViewControllercontentViewController中使用以下行:

-(void) viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    self.preferredContentSize=myTableView.contentSize;
}

希望这能帮助iOS 7用户。


9
在 ViewWillAppear 中可能效果更好,因为它发生在视图显示之前。 - nh32rg
1
如果您在弹出窗口中使用navigationController,并且即使设置了preferredContentSize仍然出现问题,请尝试在推送UIViewController之前使用[self.parentPopOverController setPopoverContentSize:CGSizeMake(250, 400) animated:YES]; - Hassy
1
接受您的答案,因为它更加更新。谢谢! - Avi Shukron
请查看下面@Robert的答案 - 简洁明了。 - amergin
1
如果表格具有默认大小,则您可能还需要使用 [myTableView sizeToFit]; 。而且,这也应该放在viewWillAppear而不是viewDidAppear方法中。 - kvn
1
在iOS 8上,这必须放在viewDidAppear中,因为当调用viewWillAppear时,self.tableView尚未正确布局,即其高度为零。 - Mojo66

9

最终,我做了一些事情,不确定是否是正确的选择,但它能够正常工作。

我在我的contentViewController中添加了一个对popoverController的引用:

@property (nonatomic , assign) UIPopoverController *popoverControllerContainer;

接着,我将调整大小的代码添加到viewWillAppear和viewDidAppear中:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView reloadData];
}

-(void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.contentSizeForViewInPopover = self.tableView.contentSize;
}

-(void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.popoverControllerContainer setPopoverContentSize:self.contentSizeForViewInPopover animated:YES];
}

因此,保留popover的引用有点hack-ish,所以我愿意听到更好的想法。


我使用相同的机制。我正在为用作弹出窗口内容的UIViewControllers添加方法createPopover。该方法从self创建一个弹出窗口,然后保存弹出窗口实例以供进一步访问。 - Sulthan
你好 @Avraham,你的答案是我使用的,并且它运行得非常好。我有一个关于你的解决方案的问题:为什么你在will appear方法中设置了视图的contentsize,而在did appear方法中设置了popover的大小?为什么不能在这两种方法中只使用一种,因为我尝试过了,但没有成功? - Julian Osorio

7

UIViewController类有一个名为contentSizeForViewInPopover的属性

self.contentSizeForViewInPopover

这将调整弹出窗口的大小,无需添加对其的引用。
为了扩展解决方案,我使用了方法rectForSection:来获取部分的大小(我的只有一个部分,所以很容易获取),然后添加导航栏的高度(似乎是20)。因此,我能够创建与完成的表视图相同大小的弹出窗口:
CGRect sectionRect = [view.tableView rectForSection:0];

if (sectionRect.size.height + 20 < POPOVER_SIZE.height)
    view.contentSizeForViewInPopover = CGSizeMake(POPOVER_SIZE.width, sectionRect.size.height + 20);
else
    view.contentSizeForViewInPopover = POPOVER_SIZE;

如果存在多个部分,则可能更难处理,我没有尝试过。只需将各个部分的高度加起来即可,但可能存在一些我不了解的间距问题。


2
它已被弃用,请使用iOS7及更高版本中的“preferredContentSize”。 - Satyam

7

适用于 iOS 7 或以上版本。

- (CGSize)preferredContentSize {
    return CGSizeMake(320, 550);
}

如果您是容器的子项,请将内容大小重定向到自己。例如,在UINavigationController子类中:

- (CGSize)preferredContentSize {
    return self.topViewController.preferredContentSize;
}

这里只是提醒其他人尝试 Robert 的方法时要注意。它非常简洁且适用于此问题。然而,如果您正在 UINavigationController 中呈现 UITableView,则可能不适用于您。在那种情况下,Avinash 的方法似乎有效。 - DenVog
@DenVog - 很好的发现。我仍然更喜欢子类化UINavigationController以从其topViewController获取其首选状态栏。通常,我发现声明所需内容的方法比设置值更好,因为它可以防止两个不同的类在具有不同值的相同属性上互相干扰,这可能会导致根据您执行操作的顺序而产生不同的结果。这与为什么在iOS 7中创建了preferredStatusBarStyle类似。 - Robert
这是唯一对我有效的解决方案。设置self.preferredContentSize没有任何效果。 - pls

2
这应该能解决问题。
override func viewWillLayoutSubviews() {
  super.viewWillLayoutSubviews()

  self.preferredContentSize = CGSizeMake(0, self.tableView.contentSize.height)}

1
我的应用程序有一个菜单,其中包含从弹出窗口发起的子菜单,并嵌入导航控制器中,即类似于 UINavigationController -> TopMenuViewController -> SubMenuViewControllerxN。
以上解决方案都对我不起作用。
我的解决方案:在我的根菜单视图控制器类中,所有其他菜单视图控制器都继承自该类,添加以下代码:
- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationController.preferredContentSize  = CGSizeMake(450.0f, 0.0f);// increase standard width (320.0)
}


- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    self.navigationController.preferredContentSize = self.tableView.contentSize;
}

0
iOS8/9的解决方案 - 只需覆盖preferredContentSize并强制表视图在返回其contentSize之前进行布局。
- (CGSize)preferredContentSize {
    [self.tableView layoutIfNeeded];
    return self.tableView.contentSize;
}

如果嵌入到UINavigationController层次结构中,这将增大视图但永远不会缩小它。 - Mojo66

0
我曾经遇到过同样的问题,但是我找到的所有答案都没有起作用。最终我自己拼凑了一些代码,现在看来效果不错。
在我的initWithCoder中,我有一个数组来保存我的值。我只需要运行这段代码:
- (id)initWithCoder:(NSCoder *)aDecoder
{
//Popover Choices

_importantChoices = [NSMutableArray array];
[_importantChoices addObject:@"Bakery"];
[_importantChoices addObject:@"Beverage Dry Mix"];
[_importantChoices addObject:@"Beverage RTD"];
[_importantChoices addObject:@"Crisps"];
[_importantChoices addObject:@"Meat"];
[_importantChoices addObject:@"Supplements"];


//Calculate size of Popover
self.clearsSelectionOnViewWillAppear = NO;
NSInteger rowsCount = [_importantChoices count];
NSInteger singleRowHeight = [self.tableView.delegate tableView:self.tableView
                                       heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
NSInteger totalRowsHeight = rowsCount * singleRowHeight;
CGFloat largestLabelWidth = 0;
for (NSString *tmp in _importantChoices) {
    CGSize labelSize = [tmp sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:20.0f]}];
    if (labelSize.width > largestLabelWidth) {
        largestLabelWidth = labelSize.width;
    }
}
CGFloat popoverWidth = largestLabelWidth + 100;     //Add a little padding to the width
self.preferredContentSize = CGSizeMake(popoverWidth, totalRowsHeight);
return self;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接