Popover z wbudowanym kontrolerem nawigacyjnym nie uwzględnia rozmiaru NAV z tyłu

Mam UIPopoverController hostujący UINavigationController, który zawiera małą hierarchię kontrolerów widoku.

Podążałem za dokumentami i dla każdego kontrolera widoku ustawiałem rozmiar kontekstu widoku tak:

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

(rozmiar inny dla każdego kontrolera)

Działa to zgodnie z oczekiwaniami, gdy poruszam się do przodu w hierarchii - wyskakujące okienko automatycznie animuje zmiany rozmiaru, aby odpowiadały pchniętemu kontrolerowi.

Jednakże, kiedy Przejdź "wstecz" przez stos widoku za pomocą przycisku Wstecz paska nawigacji, wyskakujące okienko nie zmienia rozmiaru-pozostaje tak duże, jak najgłębszy widok osiągnięty. Wydaje mi się to złamane; spodziewałbym się, że popover szanuje rozmiary, które są skonfigurowane, gdy przeskakuje przez stos widoku.

Czy coś przeoczyłem? Dzięki.
Author: Julian Król, 2010-05-02

21 answers

Ok, zmagałem się z tym samym problemem. Żadne z powyższych rozwiązań nie zadziałało dla mnie całkiem ładnie, dlatego postanowiłem przeprowadzić małe dochodzenie i dowiedzieć się, jak to działa. Oto co odkryłem: - Po ustawieniu contentSizeForViewInPopover w kontrolerze widoku nie zostanie ona zmieniona przez samo wyskakujące okienko - nawet jeśli rozmiar wyskakującego okienka może się zmienić podczas przechodzenia do innego kontrolera. - Gdy rozmiar wyskakującego zmieni się podczas przechodzenia do innego kontrolera, podczas powrotu, rozmiar popover nie przywraca - Zmiana rozmiaru popover w viewWillAppear daje bardzo dziwną animację ( gdy powiedzmy popController wewnątrz popover) - nie polecam - Dla mnie ustawienie twardego rozmiaru wewnątrz kontrolera w ogóle nie zadziała - moje Kontrolery muszą być czasami duże, czasami małe-kontroler, który je zaprezentuje, ma pomysł na rozmiar

Rozwiązanie tego bólu jest następujące: Musisz zresetować Rozmiar currentSetSizeForPopover w viewDidAppear. Ale musisz być ostrożny, gdy ustawisz ten sam rozmiar, jaki był już ustawiony w polu currentSetSizeForPopover, wtedy popover nie zmieni rozmiaru. Aby tak się stało, możesz najpierw ustawić fałszywy rozmiar (który będzie inny niż ten, który został ustawiony wcześniej), a następnie ustawić odpowiedni rozmiar. To rozwiązanie będzie działać, nawet jeśli kontroler jest zagnieżdżony wewnątrz kontrolera Nawigacyjnego, a popover zmieni odpowiednio jego rozmiar, gdy będziesz poruszać się z powrotem między kontrolerem nawigacyjnym Kontrolery.

Możesz łatwo utworzyć kategorię w UIViewController za pomocą poniższej metody pomocniczej, która zrobiłaby sztuczkę z ustawieniem rozmiaru:


- (void) forcePopoverSize {
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
    self.contentSizeForViewInPopover = fakeMomentarySize;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

Następnie po prostu wywołaj go w -viewDidAppear pożądanego kontrolera.

 94
Author: krasnyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-17 18:17:29

Oto jak rozwiązałem to dla iOS 7 i 8:

W systemie iOS 8 iOS po cichu zawija żądany widok w wyskakującym okienku do presentedViewController kontrolera widoku presentingViewController. Jest film WWDC z 2014 roku wyjaśniający, co nowego w popovercontrollerze, gdzie dotykają tego.

W każdym razie, dla kontrolerów widoków prezentowanych na stosie kontrolerów nawigacyjnych, które chcą mieć własne rozmiary, te kontrolery widoku muszą (w systemie iOS 8) wywołać ten kod dynamicznie ustawia preferredContentSize:

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

Zastąp wysokość z obliczoną tabelą lub wysokością widoku.

Aby uniknąć wielu duplikatów kodu i stworzyć wspólne rozwiązanie iOS 7 i iOS 8, utworzyłem kategorię na UITableViewController, aby wykonać tę pracę, gdy viewdidappear jest wywoływany w moich przeglądach tableviews:

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

Kategoria.h:

#import <UIKit/UIKit.h>

@interface UITableViewController (PreferredContentSize)

- (void) setPopOverViewContentSize;

@end

Kategoria.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
 18
Author: Wesley Filleman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-17 02:59:45

Jest to poprawa w odpowiedzi krasnyka .
Twoje rozwiązanie jest świetne, ale nie jest płynnie animowane.
Mała poprawa daje miłą animację:

Usuń ostatni wiersz w metodzie - (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:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self forcePopoverSize];
}

I na koniec-ustaw żądany rozmiar w metodzie - (void)viewDidAppear:(BOOL)animated:

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

    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
 12
Author: adnako,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-31 08:53:57

Musisz ponownie ustawić rozmiar zawartości w viewWillAppear. Wywołując metodę delagate, w której ustawia się rozmiar popovercontrollera. Też miałem ten sam problem. Ale kiedy to dodałem, problem rozwiązany.

Jeszcze jedno: jeśli używasz wersji beta mniejszej niż 5. Wtedy popovery są trudniejsze do zarządzania. Wydają się być bardziej przyjazne od wersji beta 5. Dobrze, że wyszła finalna wersja. ;)

Mam nadzieję, że to pomoże.
 8
Author: Madhup Singh Yadav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-07 11:03:33

W -(void)viewDidLoad wszystkich kontrolerów widoku używanych w kontrolerze nawigacyjnym dodaj:

[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
 5
Author: MouzmiSadiq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-20 12:25:12

Zresetowałem rozmiar w viewWillDisappear: (BOOL)animowana metoda kontrolera widoku, który jest nawigowany z powrotem:

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

Następnie, gdy pojawi się widok nawigowany z powrotem do, odpowiednio zresetuję Rozmiar:

-(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;
}
 3
Author: Greg C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-20 12:35:10

Dla iOS 8 działa:

- (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 myślę, że to powinno być zgodne z poprzednimi wersjami iOS...

 2
Author: Zeroid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-29 08:50:52
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 !
 2
Author: A.G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-11 06:04:58

Dla mnie To rozwiązanie działa. Jest to metoda z mojego kontrolera widoku, która rozszerza UITableViewController i jest głównym kontrolerem dla UINavigationController.

-(void)viewDidAppear:(BOOL)animated {
     [super viewDidAppear:animated];
     self.contentSizeForViewInPopover = self.tableView.bounds.size;
}

I nie zapomnij ustawić rozmiaru zawartości kontrolera widoku, który będzie wepchnięty do stosu nawigacji

- (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]; 
 }
 1
Author: Koteg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-05 06:22:28

Jeśli potrafisz sobie wyobrazić assamblera, to myślę, że to jest nieco lepsze:

- (void) forcePopoverSize {
    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = CGSizeMake(0, 0);
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
 1
Author: user1375355,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-30 04:30:26

Zaakceptowana odpowiedź nie działa dobrze z iOS 8. To, co zrobiłem, to stworzenie własnej podklasy UINavigationController do użycia w tym popover i nadpisanie metody preferredContentSize w ten sposób:

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

Ponadto, zamiast wywoływać forcePopoverSize (metodę zaimplementowaną przez @krasnyk) w viewDidAppear postanowiłem ustawić viewController (który pokazuje popover) jako delegat dla wcześniej wspomnianej nawigacji (w popover) i do (co robi metoda force) w:

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

Metoda delegowania dla zdanego viewController. Jedna ważna rzecz, Robienie forcePopoverSize w metodzie UINavigationControllerDelegate jest w porządku, jeśli nie potrzebujesz, aby animacja była płynna, jeśli tak, to zostaw ją w viewDidAppear.

 1
Author: Julian Król,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:06

Miałem ten sam problem, ale nie chcesz ustawiać contentsize w metodzie viewWillAppear lub 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];

Ustaw właściwość contentSizeForViewInPopover dla tego kontrolera przed naciśnięciem kontrolera do navigationController

 0
Author: Vikas Sawant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-03 06:38:27

Poszczęściło mi się umieszczając w widoku:

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

Chociaż może to nie animować ładnie w przypadku, gdy pchasz / popping popovers różnej wielkości. Ale w moim przypadku działa idealnie!

 0
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-21 00:43:05

Wszystko co musisz zrobić to:

-w metodzie viewwillappear w popOvers contentView dodaj poniższy fragment. Musisz podać rozmiar popOver po raz pierwszy, gdy jest ładowany.

CGSize size = CGSizeMake(width,height);
self.contentSizeForViewInPopover = size;
 0
Author: Deepukjayan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-06 18:48:12

Miałem ten problem z kontrolerem popover, którego popoverContentSize = CGSizeMake (320, 600) na początku, ale byłby większy podczas poruszania się po ContentViewController (UINavigationController).

Kontroler nav tylko pchał i popping custom uitableviewcontrollers, więc w moim custom table view controller class ' S viewDidLoad ustawiłem self.contentSizeForViewInPopover = CGSizeMake (320, 556)

44 mniej pikseli ma odpowiadać nav kontrolera Nav bar, a teraz nie mam już żadnych problemów.

 0
Author: leukosaima,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-04 21:52:32

Umieść to we wszystkich kontrolerach widoku, które wciskasz w popover

CGSize currentSetSizeForPopover = CGSizeMake(260, 390);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
                                      currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
 0
Author: alok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 06:35:54

Napotkał ten sam problem i naprawił go, ustawiając rozmiar widoku zawartości na Kontroler nawigacyjny i kontroler widoku przed umieszczeniem init 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];
 0
Author: Tomasz Dubik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 14:46:06

Chciałbym zaproponować inne rozwiązanie, ponieważ żadne z nich nie działało na mnie...

Używam go z tym https://github.com/nicolaschengdev/WYPopoverController

Po pierwszym wywołaniu popup użyj tego.

if ([sortTVC respondsToSelector:@selector(setPreferredContentSize:)]) {
   sortTVC.preferredContentSize = CGSizeMake(popoverContentSortWidth,
        popoverContentSortHeight);
}
else 
{
   sortTVC.contentSizeForViewInPopover = CGSizeMake(popoverContentSortWidth, 
        popoverContentSortHeight);
}

Następnie w tym wyskakującym okienku użyj tego.

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

}

Następnie powtórz dla widoków potomnych...

 0
Author: Jules,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 12:41:37

Jest to prawidłowy sposób w iOS7, aby to zrobić, Ustaw preferowany rozmiar zawartości w viewDidLoad dla każdego kontrolera widoku w stosie nawigacji(tylko raz). Następnie w viewWillAppear uzyskaj odniesienie do kontrolera popover i zaktualizuj tam rozmiar zawartości.

-(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];
}
 0
Author: anders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-25 18:19:22

@krasnyk rozwiązanie działało dobrze w poprzednich wersjach iOS, ale nie działa w iOS8. Poniższe rozwiązanie zadziałało dla mnie.

    - (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];
        }
    }
Nie jest to najlepsze rozwiązanie, ale działa.

Nowy UIPopoverPresentationController ma również problem ze zmianą rozmiaru: (.

 0
Author: Clement Prem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-01 07:49:43

Musisz ustawić preferredContentSizewłaściwość NavigationController w viewWillAppear:

-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}
 0
Author: Pablo Alonso González,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-21 08:28:29