Popover со встроенным навигационным контроллером не учитывает размер на заднем навигаторе

У меня есть UIPopoverController, на котором размещен UINavigationController, который содержит небольшую иерархию диспетчеров представлений.

Я следил за документами и для каждого контроллера представления, я установил размер popover-context вида так:

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

(размер отличается для каждого контроллера)

Это работает, как и ожидалось, когда я перемещаюсь по иерархии: popover автоматически анимирует изменения размера, соответствующие толкаемому контроллеру.

Однако, когда я перемещаюсь по "Назад" через стек представления с помощью кнопки "Назад" навигационной панели, popover не изменяет размер - он остается таким же большим, как и самый глубокий вид. Это кажется мне сломленным; Я ожидаю, что popover будет уважать размеры, которые настраиваются по мере того, как они появляются через стек представления.

Я что-то пропустил?

Спасибо.

Ответ 1

Хорошо, я боролся с той же проблемой. Ни одно из вышеперечисленных решений не работало для меня довольно красиво, поэтому я решил провести небольшое расследование и выяснить, как это работает. Это то, что я обнаружил: - Когда вы устанавливаете contentSizeForViewInPopover в своем контроллере просмотра, он не будет изменен самим popover - хотя размер popover может измениться при навигации к другому контроллеру. - Когда размер popover будет меняться при навигации к другому контроллеру, возвращаясь назад, размер popover не восстанавливается - Изменение размера popover в viewWillAppear дает очень странную анимацию (когда вы говорите, что вы popController внутри popover) - я бы не рекомендовал его - Для меня установка жестко заданного размера внутри контроллера не будет работать вообще - мои контроллеры должны быть иногда большими, иногда небольшими - контроллер, который будет их представлять, имеет представление о размере, хотя

Решение для всей этой боли выглядит следующим образом: Вы должны reset размер currentSetSizeForPopover в viewDidAppear. Но вы должны быть осторожны, когда вы установите тот же размер, который был уже установлен в поле currentSetSizeForPopover, тогда попсор не изменит размер. Чтобы это произошло, вы можете сначала установить поддельный размер (который будет отличаться от того, который был установлен ранее), а затем установить правильный размер. Это решение будет работать, даже если ваш контроллер вложен в контроллер навигации, и popover изменит его размер соответственно, когда вы будете перемещаться между контроллерами.

Вы можете легко создать категорию в 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 требуемого контроллера.

Ответ 2

Вот как я решил это для iOS 7 и 8:

В iOS 8 iOS молча переносит представление, которое вы хотите в popover, в представленный контроллер управления представлением viewController. Там видеоролик WWDC 2014 года, объясняющий, что нового с контроллером popover, где они касаются этого.

В любом случае, для контроллеров представлений, представленных в стеке контроллера навигации, которые все хотят иметь собственный размер, эти диспетчеры представлений нуждаются (под iOS 8), чтобы вызвать этот код, чтобы динамически установить preferredContentSize:

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

Замените heightOfTable на вычисленную таблицу или высоту представления.

Во избежание многократного дублирования кода и создания общего решения iOS 7 и iOS 8 я создал категорию в UITableViewController для выполнения этой работы, когда viewDidAppear вызывается в моих табличных представлениях:

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

Category.h:

#import <UIKit/UIKit.h>

@interface UITableViewController (PreferredContentSize)

- (void) setPopOverViewContentSize;

@end

Category.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

Ответ 3

Это улучшение в ответе 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;
}

Ответ 4

Вам нужно снова установить размер содержимого в viewWillAppear. Вызвав метод delagate, в котором вы задаете размер popovercontroller. У меня была та же проблема. Но когда я добавил, проблема решена.

Еще одна вещь: если вы используете бета-версии, меньшие, чем 5. Тогда поппостерам сложнее управлять. Они, похоже, более дружелюбны с бета-версией 5. Хорошо, что окончательная версия отсутствует.;)Забастовкa >

Надеюсь, что это поможет.

Ответ 5

В -(void)viewDidLoad всех контроллеров вида, которые вы используете в контроллере навигации, добавьте:

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

Ответ 6

I reset размер в анимационном методе viewWillDisappear: (BOOL) контроллера вида, который перемещается назад:

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    CGSize contentSize = [self contentSizeForViewInPopover];
    contentSize.height = 0.0;
    self.contentSizeForViewInPopover = contentSize;
}

Затем, когда появится представление, отображаемое назад, я reset размер соответственно:

-(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;
}

Ответ 7

Для 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...

Ответ 8

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 !

Ответ 9

Для меня эти решения работают. Это метод из моего контроллера представления, который расширяет 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]; 
 }

Ответ 10

если вы можете представить assambler, я думаю, что это немного лучше:

- (void) forcePopoverSize {
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = CGSizeMake(0, 0);
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

Ответ 11

Ответ на не работает отлично с iOS 8. Что я сделал, это создать свой собственный подкласс UINavigationController для использования в этом popover и переопределить метод preferredContentSize следующим образом:

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

Кроме того, вместо вызова forcePopoverSize (метода, реализованного @krasnyk) в viewDidAppear, я решил установить viewController (который показывает popover) как делегат для ранее упомянутой навигации (в popover) и сделать (какой метод силы ) в:

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

метод делегирования для прошедшего viewController. Одна важная вещь, выполняющая forcePopoverSize в методе UINavigationControllerDelegate, хороша, если вам не нужна эта анимация, чтобы быть гладкой, если тогда оставить ее в viewDidAppear.

Ответ 12

У меня возникла такая же проблема, но вы не хотите устанавливать контент в viewWillAppear или viewWillDisappear.

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];

установить свойство contentSizeForViewInPopover для этого контроллера, прежде чем нажимать этот контроллер на navigationController

Ответ 13

Мне повезло, поставив следующее в viewdidappear:

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

Хотя это может не приятно анимироваться в случае, когда вы нажимаете/выскакиваете по-разному по-разному. Но в моем случае отлично работает!

Ответ 14

Все, что вам нужно сделать, это:

- В методе viewWillAppear для popover контента popOvers добавьте приведенный ниже фрагмент. Сначала вам нужно будет указать размер popOver, когда он будет загружен.

CGSize size = CGSizeMake(width,height);
self.contentSizeForViewInPopover = size;

Ответ 15

У меня возникла эта проблема с контроллером popover, чья popoverContentSize = CGSizeMake (320, 600) в начале, но будет больше при навигации через ContentViewController (UINavigationController).

Контроллер nav только выталкивал и выталкивал пользовательские UITableViewControllers, поэтому в моем настраиваемом представлении таблиц контроллера класса viewDidLoad я установил self.contentSizeForViewInPopover = CGSizeMake (320, 556)

44 меньше пикселей должны учитывать навигационную панель Nav controller, и теперь у меня больше нет проблем.

Ответ 16

Поместите это во все контроллеры просмотра, которые вы нажимаете внутри popover

CGSize currentSetSizeForPopover = CGSizeMake(260, 390);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
                                      currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;

Ответ 17

Столкнулась с той же проблемой и исправила ее, установив размер представления контента на контроллер навигации и контроллер представления до того, как была помещена инициация UIPopoverController.

     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];

Ответ 18

Я просто хотел бы предложить другое решение, так как никто из них не работал у меня...

Я использую его с помощью 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;

}

Затем повторите для дочерних просмотров...

Ответ 19

Это правильный способ в 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];
}

Ответ 20

Решение @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 rootVC.
        id mainVC = [MyAppDelegate appDelegate].myRootVC;
        if ([mainVC valueForKey:@"_myPopoverController"]) {
            UIPopoverController *popover = [mainVC valueForKey:@"_myPopoverController"];
            [popover setPopoverContentSize:currentSetSizeForPopover animated:YES];
        }
    }

Это не лучшее решение, но оно работает.

Новый UIPopoverPresentationController также имеет проблему изменения размера:(.

Ответ 21

Вам нужно установить свойство preferredContentSize для NavigationController в viewWillAppear:

-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}