UIModalTransitionStylePartialCurl con UITabBarController

Esta pregunta se ha hecho mucho, por ejemplo, aquí, pero por lo que puedo ver aún no se ha respondido en su totalidad.

Tengo un UITabBarController con un UINavigationController como vc raíz para una de las tabs, que a su vez tiene un MKMapView como su raíz vc. El comportamiento que deseo es que el mapa se curve parcialmente hacia arriba, mientras deja la barra de tabs en su lugar (similar a la aplicación Mapas).

Hasta ahora, todo lo que he logrado es trabajar para que todo se curve, lo que no es tan agradable.

Las soluciones que he visto son para establecer la propiedad hidesBottomBarWhenPushed en NO, lo que tendría sentido, sin embargo, esto no parece funcionar (a menos que esté haciendo algo mal).

Para mayor claridad, mi código es el siguiente:

 MyVC *aView = [MyVC init]; aView.modalTransitionStyle = UIModalTransitionStylePartialCurl; aView.hidesBottomBarWhenPushed = NO; 

Para la parte de presentación, he intentado las dos alternativas a continuación, ninguna de las cuales parece funcionar:

 [self presentModalViewController:updateStatus animated:YES]; [[self navigationController] presentModalViewController:updateStatus animated:YES]; 

Cualquier ayuda muy apreciada.

Revisé StackOverflow (e Internet) para encontrar una solución a este problema. La pregunta se ha formulado muchas veces, pero como usted nota, nunca respondió lo suficiente. Muchas soluciones ofrecen una solución aceptable si no es importante si, por ejemplo, una barra de herramientas inferior también se curza.

Otros han proporcionado una solución usando UIView animations / CoreAnimation en lugar de UIModalTransitionStylePartialCurl como un estilo de transición modal; en el peor de los casos, esta es una solución que no está permitida y, en el mejor de los casos, no tiene el mismo efecto que uno obtiene de UIModalTransitionStylePartialCurl (por ejemplo, la forma del rizo es diferente).

Ninguna de estas soluciones ha proporcionado una respuesta que imite la solución de Apple en la aplicación Mapas (es decir, que usa UIModalTransitionStylePartialCurl pero deja una UIToolbar sin UIToolbar en la parte inferior de la pantalla).

Continuaré en esta tradición de respuestas incompletas, ya que usted pregunta acerca de un UITabBarController y mi solución no aborda específicamente ese caso. Sin embargo, resuelve el problema que tenía, que consistía en obtener un rizo de media página con una barra de herramientas sin rizar en la parte inferior.

Debe haber una forma más elegante de hacer esto, pero así es como lo logré.

El rootViewController de mi AppDelegate es una subclase de UIViewController , que llamaré TAContainerViewController . TAContainerViewController administra a) el contenido real de la pantalla (el “material a TAContentViewController “), TAContentViewController , yb) el contenido “detrás” del TAContentViewController (por ejemplo, configuraciones), que llamaré TAUnderCurlViewController .

Mi instancia de TAContainerViewController tenía propiedades para un TAContentViewController y un TAUnderCurlViewController . El UIView que era mi contenido era una subvista de la propiedad de view de TAContentViewController ; asimismo, lo que el usuario ve debajo del rizo es la propiedad de view del TAUnderCurlViewController .

En el método init de TAContainerViewController me aseguro de hacer lo siguiente:

  _underCurlVC.modalTransitionStyle = UIModalTransitionStylePartialCurl; 

Y para curvar los contenidos para revelar debajo de la página, configuro una acción que llama a este código:

  [self.contentVC presentModalViewController:self.underCurlVC animated:YES];` 

donde self es TAContainerViewController , contentVC es una instancia de TAContentViewController y underCurlVC es una instancia de TAUnderCurlViewController .

Para descartar la vista, simplemente [self.contentVC dismissModalViewControllerAnimated:YES]; .

Parece extraño que algo ocurra con el marco de contentVC cuando se descarta la vista modal, por lo que reinicio manualmente el cuadro cuando se descarta la vista modal.

He publicado un proyecto de muestra con más detalles sobre Github . Esperemos que alguien pueda tomar esto y convertirlo en una solución ligeramente más elegante, o expandirlo para que funcione con un UINavigationController o UITabBarController . Creo que el truco es sacar los Controladores de Vista de las relaciones bien definidas en las subclases de Cocoa, así que tal vez subclases de esos Controladores de Vista especiales lo hagan.

La respuesta de Tim Arnold funcionó muy bien para mí, ¡gracias!

Una trampa a tener en cuenta: su transición modal de página y curva ocupará toda la pantalla si su controlador de vista de contenido se agrega como elemento secundario del controlador de vista de contenedor . Simplemente no podría agregarlo como un niño, pero ninguno de los métodos del ciclo de vida de la vista se viewDidLoad en su controlador de contenido (por ejemplo, viewWillAppear , viewWillAppear ), lo que podría ser un problema.

Afortunadamente, hay una forma de evitar esto. En su controlador de contenedor:

  • Agregue su controlador de contenido como un niño en viewDidLoad
  • viewDidAppear como un niño en viewDidAppear
  • Vuelva a agregarlo como un niño a la viewWillDisappear . viewWillDisappear .

De esta forma, su controlador de contenido obtiene sus métodos de ciclo de vida llamados, mientras que aún puede hacer una transición modal de página-curva sin ocupar toda la pantalla.

Aquí está el código completo de una solución escueta:

 @interface XXContainerController : UIViewController @property (strong, nonatomic) UIViewController *contentController; @property (nonatomic) BOOL curled; @end @implementation XXContainerController @synthesize contentController = _contentController; @synthesize curled = _curled; - (void)viewDidLoad { [super viewDidLoad]; self.contentController = [self.storyboard instantiateViewControllerWithIdentifier:@"SomeControllerInStoryboard"]; // Add content controller as child view controller. // This way, it will receive all the view lifecycle events [self addChildViewController:self.contentController]; self.contentController.view.frame = self.view.bounds; [self.view addSubview:self.contentController.view]; [self.contentController didMoveToParentViewController:self]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // Remove the content controller as child view controller. // This way, the modal page curl transition will // not take over the whole screen. // NOTE: need to wait until content controller has appeared // (which will happen later). // Achieve this by running the code at the end of the animation loop [UIView animateWithDuration:0 animations:nil completion:^(BOOL finished) { [self.contentController removeFromParentViewController]; }]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // Add the content controller as child view controller again // so it receives the view lifecycle events [self addChildViewController:self.contentController]; } - (void)setCurled:(BOOL)curled { if (curled == _curled) return; _curled = curled; // Curl up the content view and show underneath controller's view if (curled) { // Note you can specify any modal transition in storyboard // Eg page curl, flip horizontal [self.contentController performSegueWithIdentifier:@"SomeModalSegueDefinedInStoryboard" sender:self]; // Uncurl and show the content controller's view again } else { [self.contentController dismissModalViewControllerAnimated:YES]; // Have to do this, otherwise the content controller's view // gets messed up for some reason self.contentController.view.frame = self.view.bounds; } } @end