web-dev-qa-db-fra.com

Popover avec contrôleur de navigation intégré ne respecte pas la taille de la navigation arrière

J'ai un UIPopoverController hébergeant un UINavigationController, qui contient une petite hiérarchie de contrôleurs de vue.

J'ai suivi les documents et pour chaque contrôleur de vue, j'ai défini la taille du contexte de popover de la vue comme suit:

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

(taille différente pour chaque contrôleur)

Cela fonctionne comme prévu lorsque je navigue dans la hiérarchie - le popover anime automatiquement les changements de taille pour correspondre au contrôleur poussé.

Cependant, lorsque je navigue "Retour" dans la pile de vues via le bouton Précédent de la barre de navigation, le popover ne change pas de taille - il reste aussi grand que la vue la plus profonde atteinte. Cela me semble cassé; Je m'attends à ce que le popover respecte les tailles définies lors de son apparition dans la pile de vues.

Suis-je en train de manquer quelque chose?

Merci.

88
Ben Zotto

Ok, je me débattais avec le même problème. Aucune des solutions ci-dessus n'a très bien fonctionné pour moi, c'est pourquoi j'ai décidé de faire une petite enquête et de savoir comment cela fonctionne. Voici ce que j'ai découvert: - Lorsque vous définissez le contentSizeForViewInPopover dans votre contrôleur de vue, il ne sera pas modifié par le popover lui-même - même si la taille du popover peut changer lors de la navigation vers un contrôleur différent. - Lorsque la taille du popover changera lors de la navigation vers un autre contrôleur, tout en revenant, la taille du popover ne restaure pas - La modification de la taille du popover dans viewWillAppear donne une animation très étrange (quand disons que vous popController à l'intérieur du popover) - Je ne le recommanderais pas - Pour moi, définir la taille codée en dur à l'intérieur du contrôleur ne fonctionnerait pas du tout - mes contrôleurs doivent être parfois grands parfois petits - le contrôleur qui leur présentera a cependant une idée de la taille

Une solution pour tout ce mal est la suivante: vous devez réinitialiser la taille de currentSetSizeForPopover dans viewDidAppear. Mais vous devez être prudent, lorsque vous définirez la même taille que celle déjà définie dans le champ currentSetSizeForPopover, le popover ne changera pas la taille. Pour que cela se produise, vous pouvez d'abord définir la fausse taille (qui sera différente de celle qui a été définie auparavant), puis définir la bonne taille. Cette solution fonctionnera même si votre contrôleur est imbriqué à l'intérieur du contrôleur de navigation et le popover changera sa taille en conséquence lorsque vous reviendrez entre les contrôleurs.

Vous pouvez facilement créer une catégorie sur UIViewController avec la méthode d'assistance suivante qui ferait l'affaire avec la définition de la taille:


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

Il suffit ensuite de l'invoquer dans -viewDidAppear du contrôleur souhaité.

92
krasnyk

Voici comment je l'ai résolu pour iOS 7 et 8:

Dans iOS 8, iOS enveloppe silencieusement la vue que vous souhaitez dans la fenêtre contextuelle dans le PresentViewController du contrôleur de vue PresentViewController. Il y a une vidéo de la WWDC 2014 expliquant les nouveautés du popovercontroller où ils abordent ce sujet.

Quoi qu'il en soit, pour les contrôleurs de vue présentés sur la pile de contrôleurs de navigation qui veulent tous leur propre dimensionnement, ces contrôleurs de vue doivent (sous iOS 8) appeler ce code pour définir dynamiquement le PreferredContentSize:

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

Remplacez heightOfTable par votre table calculée ou affichez la hauteur.

Afin d'éviter beaucoup de code en double et de créer une solution iOS 7 et iOS 8 commune, j'ai créé une catégorie sur UITableViewController pour effectuer ce travail lorsque viewDidAppear est appelé dans mes vues de table:

- (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
18
Wesley Filleman

Il s'agit d'une amélioration par rapport à la réponse de krasnyk.
Votre solution est excellente, mais elle n'est pas animée en douceur.
Une petite amélioration donne une belle animation:

Supprimez la dernière ligne de la méthode - (void) forcePopoverSize:

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

Mettez [self forcePopoverSize] dans la méthode - (void)viewWillAppear:(BOOL)animated:

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

    [self forcePopoverSize];
}

Et enfin - définissez la taille souhaitée dans la méthode - (void)viewDidAppear:(BOOL)animated:

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

    CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
    self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
12
adnako

Vous devez définir à nouveau la taille du contenu dans viewWillAppear. En appelant la méthode delagate dans laquelle vous définissez la taille de popovercontroller. J'avais aussi le même problème. Mais quand j'ai ajouté cela, le problème a été résolu.

Encore une chose: si vous utilisez des versions bêta inférieures à 5. Les popovers sont alors plus difficiles à gérer. Ils semblent être plus conviviaux à partir de la version bêta 5. C'est bien que la version finale soit sortie. ;)

J'espère que cela t'aides.

8

Dans la -(void)viewDidLoad de tous les contrôleurs de vue que vous utilisez dans le contrôleur de navigation, ajoutez:

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

J'ai réinitialisé la taille dans la méthode animée viewWillDisappear: (BOOL) du contrôleur de vue en cours de navigation depuis:

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

Ensuite, lorsque la vue en cours de navigation apparaît, je réinitialise la taille de manière appropriée:

-(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
Greg C
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
A.G

Pour iOS 8, les travaux suivants:

- (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 Je pense que cela devrait être compatible avec les versions précédentes d'iOS ...

2
Zeroid

réponse acceptée ne fonctionne pas correctement avec iOS 8. Ce que j'ai fait, c'est créer ma propre sous-classe de UINavigationController pour l'utiliser dans ce popover et remplacer la méthode preferredContentSize dans ce façon:

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

De plus, au lieu d'appeler forcePopoverSize (méthode implémentée par @krasnyk) dans viewDidAppear j'ai décidé de définir un viewController (qui affiche le popover) comme délégué pour la navigation mentionnée précédemment (dans le popover) et faire ( quelle force force la méthode) dans:

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

méthode déléguée pour un viewController passé. Une chose importante, faire forcePopoverSize dans une méthode UINavigationControllerDelegate est très bien si vous n'avez pas besoin que cette animation soit fluide, alors laissez-la dans viewDidAppear.

1
Julian Król

Pour moi, cette solution fonctionne. Il s'agit d'une méthode de mon contrôleur de vue qui étend UITableViewController et est le contrôleur racine pour UINavigationController.

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

Et n'oubliez pas de définir la taille du contenu pour le contrôleur de vue que vous allez pousser dans la pile de navigation

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

si vous pouvez imaginer l'assambler, je pense que c'est un peu mieux:

] 
} 
1
user1375355

C'est la bonne façon dans iOS7 de le faire, définissez la taille de contenu préférée dans viewDidLoad dans chaque contrôleur de vue de la pile de navigation (effectué une seule fois). Ensuite, dans viewWillAppear, obtenez une référence au contrôleur popover et mettez à jour le contentSize là-bas.

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

Il vous suffit de:

-Dans la méthode viewWillAppear de popOvers contentView, ajoutez l'extrait ci-dessous. Vous devrez spécifier la taille du popOver pour la première fois lors de son chargement.

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

Vous devez définir la propriété preferredContentSize du NavigationController dans viewWillAppear:

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

J'ai eu ce problème avec un contrôleur popover dont popoverContentSize = CGSizeMake (320, 600) au début, mais devenait plus gros lors de la navigation dans son ContentViewController (un UINavigationController).

Le contrôleur de navigation ne faisait que pousser et faire sauter des UITableViewControllers personnalisés, donc dans la vue de ma classe de contrôleur de vue de table personnalisée, j'ai défini self.contentSizeForViewInPopover = CGSizeMake (320, 556)

Les 44 pixels de moins doivent représenter la barre de navigation du contrôleur Nav, et maintenant je n'ai plus de problème.

0
leukosaima

A rencontré le même problème et l'a résolu en définissant la taille de la vue du contenu sur le contrôleur de navigation et le contrôleur de vue avant le lancement de l'init de 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
Tomasz Dubik

Mettez cela dans tous les contrôleurs de vue que vous poussez à l'intérieur du popover

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

La solution @krasnyk fonctionnait bien dans les versions précédentes d'iOS mais ne fonctionnait pas dans iOS8. La solution suivante a fonctionné pour moi.

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

Ce n'est pas la meilleure solution, mais cela fonctionne.

Le nouveau UIPopoverPresentationController a également le problème de redimensionnement :(.

0
Clement Prem

J'ai eu de la chance en mettant ce qui suit dans le viewdidappear:

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

Bien que cela puisse ne pas bien s'animer dans le cas où vous poussez/sautez des popovers de différentes tailles. Mais dans mon cas, fonctionne parfaitement!

0
Chris

Je voudrais juste proposer une autre solution, car aucune de ces solutions n'a fonctionné pour moi ...

Je l'utilise en fait avec cela https://github.com/nicolaschengdev/WYPopoverController

Lorsque vous appelez votre popup pour la première fois, utilisez ceci.

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

Ensuite, dans ce popup, utilisez ceci.

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

}

Répétez ensuite pour les vues enfant ...

0
Jules

J'étais confronté au même problème, mais vous ne voulez pas définir contentize dans la méthode viewWillAppear ou 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];

définissez la propriété contentSizeForViewInPopover pour ce contrôleur avant de pousser ce contrôleur vers navigationController

0
Vikas Sawant