ios 带有嵌入式导航控制器的 Popover 不考虑背面导航的大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2752394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Popover with embedded navigation controller doesn't respect size on back nav
提问by Ben Zotto
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.
谢谢。
回答by krasnyk
Ok, 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 contentSizeForViewInPopoverin 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
好的,我正在为同样的问题而苦苦挣扎。上述解决方案都不适合我,这就是为什么我决定做一些调查并找出它是如何工作的。这就是我发现的: - 当你设置contentSizeForViewInPopover在您的视图控制器也不会被酥料饼本身被改变 - 即使在导航到不同的控制器酥料饼的大小可能会改变。- 当导航到不同控制器时弹出框的大小会发生变化,而返回时,弹出框的大小不会恢复 - 在 viewWillAppear 中更改弹出框的大小会产生非常奇怪的动画(假设您在弹出框内使用 popController)-我不推荐它 - 对我来说,在控制器内设置硬编码的大小根本不起作用 - 我的控制器必须有时大有时小 - 将呈现它们的控制器有关于大小的想法
A solution for all that pain is as follows:
You have to reset the size of currentSetSizeForPopoverin viewDidAppear. But you have to be careful, when you will set the same size as was already set in field currentSetSizeForPopoverthen 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.
所有这些痛苦的解决方案如下:您必须重置currentSetSizeForPopoverviewDidAppear 中的大小。但是你必须小心,当你设置的大小与字段中已经设置的大小相同时currentSetSizeForPopover,弹出框不会改变大小。为此,您可以首先设置假尺寸(这将与之前设置的不同),然后设置适当的尺寸。即使您的控制器嵌套在导航控制器中,此解决方案也将起作用,并且当您在控制器之间导航时,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 -viewDidAppearof desired controller.
然后只需在-viewDidAppear所需的控制器中调用它。
回答by Wesley Filleman
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. There's a 2014 WWDC video explaining what's new with the popovercontroller where they touch on this.
在 iOS 8 中,iOS 会默默地将您想要的视图包含在 popover 中,放入 PresentingViewController 视图控制器的presentedViewController中。有一个 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
回答by adnako
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) forcePopoverSizemethod:
这是对krasnyk答案的改进。
您的解决方案很棒,但动画效果不佳。
一些改进提供了很好的动画:
删除- (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)animatedmethod:
将 [self forcePopoverSize] 放入- (void)viewWillAppear:(BOOL)animated方法中:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self forcePopoverSize];
}
And finally - set desired size in - (void)viewDidAppear:(BOOL)animatedmethod:
最后 - 在- (void)viewDidAppear:(BOOL)animated方法中设置所需的大小:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
回答by Madhup Singh Yadav
You need to set the content size again in viewWillAppear. By calling the delagate method in which you set the size of popovercontroller. I had also the same issue. But when I added this the problem solved.
您需要在viewWillAppear. 通过调用 delagate 方法来设置 popovercontroller 的大小。我也有同样的问题。但是当我添加这个时,问题就解决了。
One more thing: if you are using beta versions lesser than 5. Then the popovers are more difficult to manage. They seem to be more friendly from beta version 5. It's good that final version is out. ;)
还有一件事:如果您使用的是小于 5 的 beta 版本。那么弹出窗口将更难以管理。从测试版 5 开始,它们似乎更加友好。最终版本出来了,这很好。;)
Hope this helps.
希望这可以帮助。
回答by SumiSadiq
In the -(void)viewDidLoadof all the view controllers you are using in navigation controller, add:
在-(void)viewDidLoad导航控制器中使用的所有视图控制器中,添加:
[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
回答by Greg C
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;
}
回答by Zeroid
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 版本兼容...
回答by A.G
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 !
回答by Julian Król
The accepted answeris not working fine with iOS 8. What I did was creating my own subclass of UINavigationControllerfor use in that popover and override the method preferredContentSizein this way:
该接受的答案是不工作的罚款与iOS 8.我所做的就是创建我自己的子类的UINavigationController用于在酥料饼的使用和覆盖的方法preferredContentSize以这种方式:
- (CGSize)preferredContentSize {
return [[self.viewControllers lastObject] preferredContentSize];
}
Moreover, instead of calling forcePopoverSize(method implemented by @krasnyk) in viewDidAppearI decided to set a viewController (which shows popover) as a delegate for previously mentioned navigation (in popover) and do (what force method does) in:
此外,我决定设置一个 viewController(显示 popover)作为前面提到的导航(在 popover 中)的委托,而不是调用forcePopoverSize(由@krasnyk 实现的viewDidAppear方法),并在以下位置执行(强制方法的作用):
-(void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
delegate method for a passed viewController. One important thing, doing forcePopoverSizein a UINavigationControllerDelegatemethod is fine if you do not need that animation to be smooth if so then do leave it in viewDidAppear.
传递的委托方法viewController。一件重要的事情,如果您不需要该动画平滑,那么forcePopoverSize在UINavigationControllerDelegate方法中执行就可以了,如果是这样,那么请将其保留在viewDidAppear.
回答by Koteg
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];
}

