[英]Popover with embedded navigation controller doesn't respect size on back nav
I have a UIPopoverController hosting a UINavigationController, which contains a small hierarchy of view controllers.我有一个托管 UINavigationController 的 UIPopoverController,它包含一个小的视图控制器层次结构。
I followed the docs and for each view controller, I set the view's popover-context size like so:我遵循了文档,对于每个视图控制器,我设置了视图的弹出上下文大小,如下所示:
[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
(size different for each controller) (每个控制器的尺寸不同)
This works as expected as I navigate forward in the hierarchy-- the popover automatically animates size changes to correspond to the pushed controller.当我在层次结构中向前导航时,这按预期工作 - 弹出框自动动画大小更改以对应于推送的控制器。
However, when I navigate "Back" through the view stack via the navigation bar's Back button, the popover doesn't change size-- it remains as large as the deepest view reached.但是,当我通过导航栏的“后退”按钮在视图堆栈中“返回”导航时,弹出框的大小不会改变——它仍然与到达的最深视图一样大。 This seems broken to me;
这对我来说似乎坏了; I'd expect the popover to respect the sizes that are set up as it pops through the view stack.
我希望弹出窗口尊重它在视图堆栈中弹出时设置的大小。
Am I missing something?我错过了什么吗?
Thanks.谢谢。
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:这是我发现的:
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.contentSizeForViewInPopover
,它不会被弹出框本身更改 - 即使导航到不同控制器时弹出框大小可能会发生变化。A solution for all that pain is as follows:解决所有这些痛苦的方法如下:
You have to reset the size of currentSetSizeForPopover
in viewDidAppear.您必须在 viewDidAppear 中重置
currentSetSizeForPopover
的大小。 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.但是你必须小心,当你设置的大小与字段
currentSetSizeForPopover
已经设置的大小相同时,弹出框不会改变大小。 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.
即使您的控制器嵌套在导航控制器中,此解决方案也将起作用,并且当您在控制器之间导航时,popover 将相应地更改其大小。
You could easily create category on UIViewController with the following helper method that would do the trick with setting the size:您可以使用以下辅助方法轻松在 UIViewController 上创建类别,该方法可以设置大小:
- (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.然后只需在所需控制器的
-viewDidAppear
中调用它。
Here's how I solved it for iOS 7 and 8:以下是我为 iOS 7 和 8 解决的方法:
In iOS 8, iOS is silently wrapping the view you want in the popover into the presentedViewController of the presentingViewController view controller.在 iOS 8 中,iOS 会默默地将您想要的视图包含在 popover 中,放入 PresentingViewController 视图控制器的presentedViewController中。 There's a 2014 WWDC video explaining what's new with the popovercontroller where they touch on this.
有一个 2014 年的 WWDC 视频解释了 popovercontroller 的新功能,他们在那里触及了这一点。
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:无论如何,对于在导航控制器堆栈上显示的视图控制器都需要自己的大小,这些视图控制器需要(在 iOS 8 下)调用此代码来动态设置 preferredContentSize:
self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);
Replace heightOfTable with your computed table or view height.将 heightOfTable 替换为您计算出的表格或视图高度。
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:为了避免大量重复代码并创建通用的 iOS 7 和 iOS 8 解决方案,我在 UITableViewController 上创建了一个类别,以便在我的 tableview 中调用 viewDidAppear 时执行此工作:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self setPopOverViewContentSize];
}
Category.h:类别.h:
#import <UIKit/UIKit.h>
@interface UITableViewController (PreferredContentSize)
- (void) setPopOverViewContentSize;
@end
Category.m:类别.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.这是对krasnyk答案的改进。
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
方法中的最后一行:
- (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:将 [self forcePopoverSize] 放入
- (void)viewWillAppear:(BOOL)animated
方法:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self forcePopoverSize];
}
And finally - set desired size in - (void)viewDidAppear:(BOOL)animated
method:最后 - 在
- (void)viewDidAppear:(BOOL)animated
方法中设置所需的大小:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
You need to set the content size again in viewWillAppear
.您需要在
viewWillAppear
再次设置内容大小。 By calling the delagate method in which you set the size of popovercontroller.通过调用 delagate 方法来设置 popovercontroller 的大小。 I had also the same issue.
我也有同样的问题。 But when I added this the problem solved.
但是当我添加这个时,问题就解决了。
One more thing: if you are using beta versions lesser than 5. Then the popovers are more difficult to manage.
还有一件事:如果您使用的是小于 5 的 beta 版本。那么弹出窗口将更难以管理。
They seem to be more friendly from beta version 5. It's good that final version is out.
从测试版 5 开始,它们似乎更加友好。最终版本出来了,这很好。
;)
;)
Hope this helps.希望这可以帮助。
在导航控制器中使用的所有视图控制器的-(void)viewDidLoad
中,添加:
[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
I reset the size in the viewWillDisappear:(BOOL)animated method of the view controller that is being navigated back from:我在视图控制器的 viewWillDisappear:(BOOL)animated 方法中重置了大小,该方法正在从以下位置导航回来:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
CGSize contentSize = [self contentSizeForViewInPopover];
contentSize.height = 0.0;
self.contentSizeForViewInPopover = contentSize;
}
Then when the view being navigated back to appears, I reset the size appropriately:然后当被导航回的视图出现时,我适当地重置大小:
-(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;
}
For iOS 8 the following works:对于 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;
}
BTW I think, this should be compatible with previous iOS versions...顺便说一句,我认为,这应该与以前的 iOS 版本兼容...
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 !
if you can imagine the assambler, I think this is slightly better:如果你能想象一下 ssambler,我觉得这个稍微好一点:
- (void) forcePopoverSize { CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover; self.contentSizeForViewInPopover = CGSizeMake(0, 0); self.contentSizeForViewInPopover = currentSetSizeForPopover; }
The accepted answer is not working fine with iOS 8. What I did was creating my own subclass of UINavigationController
for use in that popover and override the method preferredContentSize
in this way:接受的答案不适用于 iOS 8。我所做的是创建自己的
UINavigationController
子类以在该弹出窗口中使用,并以这种方式覆盖方法preferredContentSize
:
- (CGSize)preferredContentSize {
return [[self.viewControllers lastObject] preferredContentSize];
}
Moreover, instead of calling forcePopoverSize
(method implemented by @krasnyk) in viewDidAppear
I decided to set a viewController (which shows popover) as a delegate for previously mentioned navigation (in popover) and do (what force method does) in:此外,我没有在
viewDidAppear
中调用forcePopoverSize
(由@krasnyk 实现的方法),而是决定设置一个 viewController(显示 popover)作为前面提到的导航(在 popover 中)的委托,并在以下内容中执行(强制方法的作用):
-(void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
delegate method for a passed viewController
.传递的
viewController
委托方法。 One important thing, doing forcePopoverSize
in a UINavigationControllerDelegate
method is fine if you do not need that animation to be smooth if so then do leave it in viewDidAppear
.一件重要的事情,在
UINavigationControllerDelegate
方法中执行forcePopoverSize
很好,如果您不需要该动画是平滑的,那么就将它留在viewDidAppear
。
For me this solutions works.对我来说,这个解决方案有效。 This is a method from my view controller which extends UITableViewController and is the root controller for UINavigationController.
这是我的视图控制器中的一个方法,它扩展了 UITableViewController 并且是 UINavigationController 的根控制器。
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.contentSizeForViewInPopover = self.tableView.bounds.size;
}
And don't forget to set content size for view controller you gonna push into navigation stack并且不要忘记为要推入导航堆栈的视图控制器设置内容大小
- (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];
}
All that you have to do is:您所要做的就是:
-In the viewWillAppear method of the popOvers contentView, add the snippet given below. - 在 popOvers contentView 的 viewWillAppear 方法中,添加下面给出的代码段。 You will have to specify the popOver's size first time when it is loaded.
第一次加载时,您必须指定 popOver 的大小。
CGSize size = CGSizeMake(width,height);
self.contentSizeForViewInPopover = size;
I had this issue with a popover controller whose popoverContentSize = CGSizeMake(320, 600) at the start, but would get larger when navigating through its ContentViewController (a UINavigationController).我在开始时 popoverContentSize = CGSizeMake(320, 600) 的 popover 控制器遇到了这个问题,但是在通过其 ContentViewController(一个 UINavigationController)导航时会变大。
The nav controller was only pushing and popping custom UITableViewControllers, so in my custom table view controller class's viewDidLoad i set self.contentSizeForViewInPopover = CGSizeMake(320, 556)导航控制器只是推送和弹出自定义 UITableViewControllers,所以在我的自定义表视图控制器类的 viewDidLoad 我设置 self.contentSizeForViewInPopover = CGSizeMake(320, 556)
The 44 less pixels are to account for the Nav controller's nav bar, and now I don't have any issues anymore.少了 44 个像素是为了说明导航控制器的导航栏,现在我没有任何问题了。
Put this in all view controllers you are pushing inside the popover把它放在你在弹出窗口中推送的所有视图控制器中
CGSize currentSetSizeForPopover = CGSizeMake(260, 390);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
Faced the same issue and fixed it by setting content view size to navigation controller and view controller before the init of UIPopoverController was placed.面临同样的问题并通过在放置 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];
I'd just like to offer up another solution, as none of these worked for me...我只想提供另一种解决方案,因为这些都不适合我......
I'm actually using it with this https://github.com/nicolaschengdev/WYPopoverController我实际上将它与这个https://github.com/nicolaschengdev/WYPopoverController 一起使用
When you first call your popup use this.当您第一次调用您的弹出窗口时,请使用它。
if ([sortTVC respondsToSelector:@selector(setPreferredContentSize:)]) {
sortTVC.preferredContentSize = CGSizeMake(popoverContentSortWidth,
popoverContentSortHeight);
}
else
{
sortTVC.contentSizeForViewInPopover = CGSizeMake(popoverContentSortWidth,
popoverContentSortHeight);
}
Then in that popup use this.然后在那个弹出窗口中使用这个。
-(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;
}
Then repeat for child views...然后对子视图重复...
This is the correct way in iOS7 to do this, Set the preferred content size in viewDidLoad in each view controller in the navigation stack (only done once).这是在 iOS7 中执行此操作的正确方法,在导航堆栈中的每个视图控制器中的 viewDidLoad 中设置首选内容大小(仅完成一次)。 Then in viewWillAppear get a reference to the popover controller and update the contentSize there.
然后在 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];
}
@krasnyk solution worked well in previous iOS versions but not working in iOS8. @krasnyk 解决方案在以前的 iOS 版本中运行良好,但在 iOS8 中不起作用。 The following solution worked for me.
以下解决方案对我有用。
- (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];
}
}
It is not the best solution, but it works.这不是最好的解决方案,但它有效。
The new UIPopoverPresentationController also has the resizing issue :( .新的 UIPopoverPresentationController 也有调整大小的问题:(。
You need to set the preferredContentSize
property of the NavigationController in viewWillAppear
:您需要在
viewWillAppear
设置 NavigationController 的preferredContentSize
属性:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}
I was facing same problem, but you don't want to set contentsize in viewWillAppear or viewWillDisappear method.我遇到了同样的问题,但您不想在 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];
set contentSizeForViewInPopover property for that controller before pushing that controller to navigationController在将该控制器推送到 navigationController 之前为该控制器设置 contentSizeForViewInPopover 属性
I've had luck by putting the following in the viewdidappear:通过将以下内容放入 viewdidappear,我很幸运:
[self.popoverController setPopoverContentSize:self.contentSizeForViewInPopover animated:NO];
Although this may not animate nicely in the case when you're pushing/popping different-sized popovers.尽管在您推动/弹出不同大小的弹出框时,这可能不会很好地动画化。 But in my case, works perfectly!
但就我而言,效果很好!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.