bar iphone cocoa-touch uinavigationcontroller rotation

iphone - uinavigationbar ios



UINavigationController y autorotaciĆ³n. (7)

Entonces, este fastidioso error llega muy lejos de iOS 1 a iOS 4.

Creo que la mejor solución es duplicar este error y hacerle saber a Apple que realmente queremos que se solucione. Acabo de informar de nuevo bajo el ID de error 8478525.

Tengo un UIViewController que devuelve YES en shouldAutorotateToInterfaceOrientation: para UIDeviceOrientationPortrait y NO para todo lo demás. Con esa vista en la parte superior de la pila, uso pushViewController:animated: para empujar un nuevo UIViewController . El nuevo controlador devuelve YES a cualquier cosa en shouldAutorotateToInterfaceOrientation:

La primera vista se niega a girar (como se esperaba). Una vez que se presiona la segunda vista, el usuario puede rotar el dispositivo y la IU girará (también como se esperaba). Si la segunda vista está en modo horizontal y el usuario presiona el botón Atrás (que llama popViewControllerAnimated: , la primera vista aparecerá girada ( ¡inesperadamente! ).

Si el usuario gira el dispositivo de nuevo a la orientación vertical, la vista girará y luego quedará bloqueada en el modo vertical como antes. Esto funciona, pero es feo para el usuario hasta que vuelven a girar. Así que estoy en busca de una forma de hacer que esta vista permanezca en modo retrato.

La única solución que he encontrado hasta ahora es usar -[UIDevice setOrientation:] , que -[UIDevice setOrientation:] una advertencia (la orientation es de solo lectura) pero funciona porque está realmente definida. Este es un gran hack y me gustaría una solución real. En busca de una solución real, adjunté GDB a la aplicación de Fotos (MobileSlideshow.app) y descubrí que también usa -[UIDevice setOrientation:] . Siendo una aplicación interna aunque supongo que tienen reglas diferentes.

¿Hay una manera correcta de lograr el comportamiento esperado de autorrotación?


Estaba a punto de decirte que probablemente no había manera, pero entonces tuve un pensamiento. Sería difícil hacerlo bien, pero podría hacerlo funcionar si usó dos UINavigationController : uno que controle la vista raíz y prohíba la rotación, y otro para las vistas secundarias que lo permitan. Manejaría manualmente la transición hacia y desde el controlador raíz y el controlador secundario.

Tendrías que parchar el controlador de navegación infantil para tener el botón de retroceso correcto. Y, por supuesto, tendrías que manejar el botón Atrás presionando tu mismo. Probablemente tendría que usar una UINavigationBar para hacer la animación de un controlador de navegación al siguiente para que la transición se vea bien. También tendrías que animar la transición de "empuje" entre los controladores de navegación, lo que podría requerir un poco de ajuste para que se vea bien. Usted tendría que:

  1. Configure una barra de navegación ficticia para que coincida exactamente con el controlador de navegación saliente y colóquela directamente encima de la barra del controlador de navegación. (Podría copiar la configuración del UINavigationItem del controlador de la vista actual y presionarlo)
  2. Coloque el nuevo controlador de navegación fuera de la pantalla en el borde derecho
  3. Animar el movimiento de los cuadros de los controladores nuevos y antiguos de derecha a izquierda
  4. Cree una copia del UINavigationItem para el controlador de vista entrante y empújelo en la barra de navegación ficticia
  5. Cuando se complete la animación, elimine la UINavigationBar ficticia de la vista y también el controlador de navegación saliente.

Todo esto es mucho trabajo, pero si eres muy inteligente (y muy tenaz), puedes lograr que funcione. Me encantaría ver el resultado!

Dicho esto, puede que sea mejor usar setOrientation: y arriesgarse con el proceso de aprobación de la App Store ;-)


Ha sido un post antiguo pero ya no se ha resuelto. Me gustaría compartir mi solución, para cualquier otra persona que pueda tener un dolor de cabeza.

Objetivo: un controlador UINavigation y la mayoría de los controladores de vista en su pila fijos en vertical, a excepción de un controlador de vista en la pila que puede rotar tanto en vertical como en horizontal.

Problema: de forma intuitiva, establezco un selectivo shouldAutorotateToInterfaceOrientation comprobando si topViewController es rotableViewController. Sin embargo, después de regresar desde el control giratorio del controlador en el modo horizontal, el controlador de navegación ahora se muestra en el modo horizontal aunque no está permitido.

Solución: El asesino es no permitir la rotación en la vista. viewWillAppear y presentará y descartará un modalViewController sin animación.

  1. Se agrega un appViewController a la ventana como host viewController, es decir, rooter que RootViewController;
  2. Se agrega un navigationController al appViewController, con el delegado establecido en appViewController;
  3. En el AppViewController


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if (interfaceOrientation == UIInterfaceOrientationPortrait) return YES; return canRotate; }


- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { [viewController viewDidAppear:animated]; canRotate = ([navigationController.topViewController isKindOfClass:[MyRotatable class]]); }


- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { [viewController viewWillAppear:animated]; if (![navigationController.topViewController isKindOfClass:[MyRotatable class]]) { canRotate = NO; UIViewController * blanck = [[UIViewController alloc] initWithNibName:nil bundle:nil]; [self presentModalViewController:blanck animated:NO]; [self dismissModalViewControllerAnimated:NO]; [blanck release]; } }


He encontrado una buena solución para este problema. La clave es admitir todas las orientaciones para todas las vistas en UINavigationController .

Tengo 2 vistas en el controlador. La vista raíz es solo compatible con LandscapeRight , y la segunda es compatible con LandscapeRight y Portrait .

La segunda vista shouldAutorotateToInterfaceOrientation método de shouldAutorotateToInterfaceOrientation para la shouldAutorotateToInterfaceOrientation , y se ve como siempre:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIInterfaceOrientationPortrait); }

La solución en sí misma está contenida en la fuente de la vista raíz. Ahora la vista de la raíz gira en términos de código, pero el usuario no puede verla.

//auxiliary function -(void) fixOrientation:(UIInterfaceOrientation)orientation { if (orientation == UIInterfaceOrientationPortrait) self.view.transform = CGAffineTransformMakeRotation(M_PI_2); else if (orientation == UIInterfaceOrientationLandscapeRight) self.view.transform = CGAffineTransformMakeRotation(0); } -(void) viewWillAppear:(BOOL)animated { [self fixOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { [self fixOrientation:interfaceOrientation]; //notice, that both orientations are accepted return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIInterfaceOrientationPortrait); } //these two functions helps to avoid blinking - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [UIView setAnimationsEnabled:NO]; // disable animations temporarily } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [UIView setAnimationsEnabled:YES]; // rotation finished, re-enable them }


Inténtalo de nuevo con el sistema operativo 3.0 (ahora que podemos hablar de ello). Dos casos especiales de esto se han resuelto en 3.0:

  1. Presentación de una vista modal de retrato sobre una vista de paisaje y viceversa. Un ejemplo es el comportamiento anterior a 3.0 en Mail para ver archivos adjuntos. Podría rotar a horizontal para un PDF y recuperar la vista de retrato para el mensaje cuando descartó la vista de adjuntos. (Ahora que tenemos una vista de mensaje horizontal en 3.0, este comportamiento parece haberse ido).

  2. Mezcla las orientaciones dentro de una pila de vistas y recupera la orientación correcta al abrir la pila. Un ejemplo es la transición entre la vista de tabla de películas y la vista de película en la aplicación YouTube.

Parece que ha habido algunos problemas estéticos espinosos de cómo deben verse las transiciones predeterminadas de todas las permutaciones. Hay algunos elementos extraños si los ves en cámara lenta, pero superan las inclinaciones hacia atrás en tu propio código.


Una alternativa legal a UIDevice setOrientation es la siguiente:

UIWindow* window = UIApplication.sharedApplication.keyWindow; UIView* view = [window.subviews objectAtIndex:0]; [view removeFromSuperview]; [window addSubview:view];

Esto obliga al controlador de la vista actual a evaluar su orientación, invocando aAutorotateToInterfaceOrientation y alejándose de cualquier orientación prohibida.

Por ejemplo, el siguiente código se usaría en un controlador de vista que admite todas las orientaciones pero cuyo padre solo admite el paisaje:

- (void)popBack { [self.navigationController popToRootViewControllerAnimated:YES]; } - (IBAction)backPressed:(id)sender { portraitOrientationPermitted = NO; // Force the framework to re-evaluate the interface orientation. UIWindow* window = UIApplication.sharedApplication.keyWindow; UIView* view = [window.subviews objectAtIndex:0]; [view removeFromSuperview]; [window addSubview:view]; [self performSelector:@selector(popBack) withObject:nil afterDelay:0.8]; portraitOrientationPermitted = YES; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return portraitOrientationPermitted || UIInterfaceOrientationIsLandscape(interfaceOrientation); }


iOS 5 agrega + [UIViewController intentRotationToDeviceOrientation], lo que me soluciona el problema.