简体   繁体   English

带有嵌入式导航控制器的 Popover 不考虑背面导航的大小

[英]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:这是我发现的:

  • When you set the 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 ,它不会被弹出框本身更改 - 即使导航到不同控制器时弹出框大小可能会发生变化。
  • 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在 viewWillAppear 中更改弹出框的大小会产生非常奇怪的动画(假设您在弹出框内使用 popController) - 我不推荐它
  • 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对我来说,在控制器内部设置硬编码的大小根本不起作用 - 我的控制器必须有时大有时小 - 将呈现它们的控制器虽然有关于大小的想法

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.

相关问题 Popover 控制器不尊重设备尺寸等级 - Popover controller does not respect device size class 错误的Popover大小-在Popover中的Navigation Controller下显示UITableViews时 - Incorrect Popover size - when displaying UITableViews under Navigation Controller in Popover ApplicationWindow不遵守大小 - ApplicationWindow doesn't respect size 以编程方式从导航控制器中嵌入的视图中消除弹出窗口 - Programmatically dismiss popover from view embedded in navigation controller 在导航控制器视图中导航时不加载 - When navigating back in navigation controller view doesn't load 导航控制器中的后退按钮与pushViewController没有什么关系? - What does the back button in a navigation controller do that pushViewController doesn't? 视图控制器不尊重“largeTitleDisplayMode” - view controller doesn't respect “largeTitleDisplayMode” 在iPad上弹出导航视图控制器时更改弹出控制器的大小 - changing the size of the popover controller when pushing navigation view controller in popover on iPad 通过嵌入式视图控制器返回导航控制器内部 - going back inside navigation controller through embedded view controller ViewController 内容大小不会改变弹出框大小 - ViewController content size doesn't change popover size
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM