ios - Popover con controlador de navegación integrado no respeta el tamaño del navegador trasero
uiviewcontroller uinavigationcontroller (21)
Tengo un UIPopoverController que aloja un UINavigationController, que contiene una pequeña jerarquía de controladores de visualización.
Seguí los documentos y para cada controlador de vista, configuré el tamaño de contexto de popover de la vista de la siguiente manera:
[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
(tamaño diferente para cada controlador)
Esto funciona como se esperaba a medida que avanzo en la jerarquía: el popover anima automáticamente los cambios de tamaño para corresponder al controlador empujado.
Sin embargo, cuando navego "Atrás" a través de la pila de vistas a través del botón Atrás de la barra de navegación, el popover no cambia de tamaño; sigue siendo tan grande como la vista más profunda alcanzada. Esto me parece roto; Espero que el popover respete los tamaños que se configuran a medida que aparece en la pila de vistas.
¿Me estoy perdiendo de algo?
Gracias.
Así es como lo resolví para iOS 7 y 8:
En iOS 8, iOS encapsula silenciosamente la vista que desea en el popover en el ViewViewController presentado del controlador de vista presentingViewController. Hay un video WWDC 2014 explicando qué hay de nuevo con el controlador popover donde tocan esto.
De todos modos, para los controladores de vista presentados en la pila del controlador de navegación que todos quieren su propio tamaño, estos controladores de vista necesitan (en iOS 8) llamar a este código para establecer dinámicamente el ContenidoContexto preferido:
self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);
Reemplace heightOfTable con su tabla calculada o altura de vista.
Para evitar una gran cantidad de código duplicado y para crear una solución común iOS 7 e iOS 8, creé una categoría en UITableViewController para realizar este trabajo cuando se llama a viewDidAppear en mis tablas:
- (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
En el -(void)viewDidLoad
de todos los controladores de vista que está usando en el controlador de navegación, agregue:
[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
Enfrentó el mismo problema y lo solucionó al establecer el tamaño de la vista de contenido en el controlador de navegación y ver el controlador antes de que se iniciara el inicio 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];
Esta es la forma correcta en iOS7 para hacer esto. Configure el tamaño de contenido preferido en viewDidLoad en cada controlador de vista en la pila de navegación (solo se hace una vez). Luego, en viewWillAppear, obtenga una referencia al controlador popover y actualice allí el 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];
}
Estaba enfrentando el mismo problema, pero no desea configurar el contenido en viewWillAppear o viewWillDisappear method.
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];
establecer la propiedad contentSizeForViewInPopover para ese controlador antes de empujar ese controlador a navigationController
Esto es una mejora en la respuesta de Krasnyk .
Su solución es genial, pero no está animada sin problemas.
Una pequeña mejora da una buena animación:
Elimine la última línea del método - (void) forcePopoverSize
:
- (void) forcePopoverSize {
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
}
Ponga [self forcePopoverSize] en - (void)viewWillAppear:(BOOL)animated
método - (void)viewWillAppear:(BOOL)animated
:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self forcePopoverSize];
}
Y finalmente - configure el tamaño deseado en - (void)viewDidAppear:(BOOL)animated
método - (void)viewDidAppear:(BOOL)animated
:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
La respuesta aceptada no está funcionando bien con iOS 8. Lo que hice fue crear mi propia subclase de UINavigationController
para usar en ese popover y anular el método preferredContentSize
de esta manera:
- (CGSize)preferredContentSize {
return [[self.viewControllers lastObject] preferredContentSize];
}
Además, en lugar de llamar a forcePopoverSize
(método implementado por @krasnyk) en viewDidAppear
decidí establecer un viewController (que muestra popover) como un delegado para la navegación mencionada anteriormente (en popover) y hacer (qué método de fuerza hace) en:
-(void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
delegar método para un viewController
pasado. Una cosa importante, haciendo forcePopoverSize
en un método UINavigationControllerDelegate
está bien si no necesita que la animación sea fluida si es así, déjela en viewDidAppear
.
La solución de @krasnyk funcionó bien en versiones anteriores de iOS pero no en iOS8. La siguiente solución funcionó para mí.
- (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];
}
}
No es la mejor solución, pero funciona.
El nuevo UIPopoverPresentationController también tiene el problema de cambio de tamaño :(.
Me gustaría ofrecer otra solución, ya que ninguno de estos me funcionó ...
En realidad, lo estoy usando con este https://github.com/nicolaschengdev/WYPopoverController
Cuando llame por primera vez a su ventana emergente, use esto.
if ([sortTVC respondsToSelector:@selector(setPreferredContentSize:)]) {
sortTVC.preferredContentSize = CGSizeMake(popoverContentSortWidth,
popoverContentSortHeight);
}
else
{
sortTVC.contentSizeForViewInPopover = CGSizeMake(popoverContentSortWidth,
popoverContentSortHeight);
}
Luego, en esa ventana emergente, usa esto.
-(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;
}
Luego repita para las vistas de los niños ...
Ok, estaba luchando con el mismo problema. Ninguna de las soluciones anteriores funcionó muy bien para mí, es por eso que decidí investigar un poco y descubrir cómo funciona esto. Esto es lo que descubrí: - Cuando configuras el contentSizeForViewInPopover
en tu controlador de vista, el propio popover no lo cambiará, incluso aunque el tamaño del popover pueda cambiar mientras navegas hacia un controlador diferente. - Cuando el tamaño del popover cambiará mientras navegas hacia un controlador diferente, mientras retrocedes, el tamaño del popover no se restaura. El cambio de tamaño del popover en viewWillAppear da una animación muy extraña (cuando digamos que popController dentro del popover) - No lo recomendaría. Para mí, configurar el tamaño del disco duro dentro del controlador no funcionaría en absoluto; mis controladores tienen que ser a veces grandes, a veces pequeños; el controlador que los presentará tendrá la idea del tamaño.
Una solución para todo ese dolor es la siguiente: debe restablecer el tamaño de currentSetSizeForPopover
en viewDidAppear. Pero debe tener cuidado, cuando configure el mismo tamaño que ya estaba configurado en el campo currentSetSizeForPopover
entonces el popover no cambiará el tamaño. Para que esto suceda, primero puede establecer el tamaño falso (que será diferente al que se configuró anteriormente) y luego establecer el tamaño adecuado. Esta solución funcionará incluso si su controlador está anidado dentro del controlador de navegación y Popover cambiará su tamaño según corresponda cuando navegará de regreso entre los controladores.
Podrías crear fácilmente categoría en UIViewController con el siguiente método de ayuda que haría el truco para configurar el tamaño:
- (void) forcePopoverSize {
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
A continuación, -viewDidAppear
en -viewDidAppear
del controlador deseado.
Para iOS 8, lo siguiente funciona:
- (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;
}
Por cierto, creo que esto debería ser compatible con las versiones anteriores de iOS ...
Para mí, esta solución funciona. Este es un método de mi controlador de vista que amplía UITableViewController y es el controlador raíz para UINavigationController.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.contentSizeForViewInPopover = self.tableView.bounds.size;
}
Y no te olvides de configurar el tamaño del contenido para el controlador de vista que vas a insertar en la pila de navegación
- (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];
}
Pon esto en todos los controles de vista que estás empujando dentro del popover
CGSize currentSetSizeForPopover = CGSizeMake(260, 390);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
Restablecí el tamaño en el método animado viewWillDisappear: (BOOL) del controlador de vista del que se está navegando desde:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
CGSize contentSize = [self contentSizeForViewInPopover];
contentSize.height = 0.0;
self.contentSizeForViewInPopover = contentSize;
}
Luego, cuando aparece la vista que se vuelve a navegar, restablezco el tamaño de forma apropiada:
-(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;
}
Todo lo que tienes que hacer es:
-En el método viewWillAppear de popOvers contentView, agregue el fragmento dado a continuación. Tendrá que especificar el tamaño del popOver por primera vez cuando se carga.
CGSize size = CGSizeMake(width,height);
self.contentSizeForViewInPopover = size;
Tuve este problema con un controlador de popover cuyo popoverContentSize = CGSizeMake (320, 600) al comienzo, pero que se agrandaba cuando navegaba a través de su ContentViewController (un UINavigationController).
El controlador de navegación solo empujaba y mostraba UITableViewControllers personalizados, así que en viewDidLoad de mi clase de controlador de vista personalizada establecí self.contentSizeForViewInPopover = CGSizeMake (320, 556)
Los 44 píxeles menos son para dar cuenta de la barra de navegación del controlador de Nav, y ahora ya no tengo ningún problema.
Tuve suerte al poner lo siguiente en viewdidappear:
[self.popoverController setPopoverContentSize:self.contentSizeForViewInPopover animated:NO];
Aunque puede que esto no se anime muy bien en el caso cuando está presionando / haciendo pop-ups de diferentes tamaños. Pero en mi caso, ¡funciona a la perfección!
si puedes imaginar el ensamblador, creo que esto es un poco mejor:
- (void) forcePopoverSize { CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover; self.contentSizeForViewInPopover = CGSizeMake(0, 0); self.contentSizeForViewInPopover = currentSetSizeForPopover; }
viewWillAppear
configurar la propiedadContentSize preferredContentSize
del NavigationController en viewWillAppear
:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}
viewWillAppear
volver a configurar el tamaño del contenido en viewWillAppear
. Llamando al método delagate en el que configura el tamaño de popovercontroller. También tuve el mismo problema. Pero cuando agregué esto, el problema fue resuelto.
Una cosa más: si está utilizando versiones beta menores de 5. Entonces los popovers son más difíciles de administrar. Parecen ser más amigables desde la versión beta 5. Es bueno que la versión final esté disponible. ;)
Espero que esto ayude.
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 !