13

Tengo un controlador de navegación que tiene algunos controles de vista. Necesito admitir todas las orientaciones para todos los controladores de vista excepto un controlador de vista especial que solo admite paisaje. Este controlador de vista especial aparece en el medio de la pila de navegación. He investigado bastante pero no he encontrado una buena solución. Aquí están los enlaces que he leído y probado.Paisaje de soporte para una sola vista en UINavigationController

http://www.iphonedevsdk.com/forum/iphone-sdk-development/3219-force-landscape-mode-one-view.html#post60435

How to rotate screen to landscape?

How to autorotate from portrait to landscape mode? iPhone - allow landscape orientation on just one viewcontroller http://goodliffe.blogspot.com/2009/12/iphone-forcing-uiview-to-reorientate.html

A continuación voy a tratar de sustituir mando de navegación con presentModalViewController con el fin de mostrar el controlador de vista especial. Luego voy a crear un nuevo controlador de vista de navegación dentro del controlador de vista especial para impulsar los controladores de vista posteriores.

Si alguien tiene una idea mejor, hágamelo saber. ¡Muy apreciado!

ACTUALIZACIÓN: He utilizar con éxito el método que he descrito anteriormente: sustituir pushViewController con presentModalViewController y crear un nuevo controlador de navegación.

+0

¿podría compartir el código de muestra? –

Respuesta

8

Cada vista empujado sobre la navegación de los controladores de la pila tiene que soportar las mismas orientaciones. Esto significa que no es posible tener algunos controles de vista que solo admitan retrato y otros que solo admitan paisaje.En otras palabras, todos los controladores de vista sobre la misma pila de mando de navegación debe devolver la misma en el delegado:

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 

Pero hay una solución simple para esto! Aquí hay un ejemplo para pasar de retrato a paisaje. Aquí están los pasos para hacerlo y debajo está el código para apoyarlo.

  1. Crea un controlador de vista "falso" que se enrutará en un controlador secundario de navegación. Este controlador de vista debe ser compatible con el paisaje.
  2. crear una nueva instancia de un UINavigationController, añadir una instancia del controlador de 'falso' Ver como raíz y una instancia de su controlador de vista paisaje como segundo controlador de vista
  3. presente la instancia UINavigationController como modal desde el controlador de vista padre

en primer lugar, crear un nuevo controlador de vista (FakeRootViewController) con este código:

@interface FakeRootViewController : UIViewController 
@property (strong, nonatomic) UINavigationController* parentNavigationController; 
@end 

@implementation FaceRootViewController 
@synthesize parentNavigationController; 
// viewWillAppear is called when we touch the back button on the navigation bar 
(void)viewWillAppear:(BOOL)animated { 
    // Remove our self from modal view though the parent view controller 
    [parentNavigationController dismissModalViewControllerAnimated:YES]; 
} 
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    return (interfaceOrientation == UIInterfaceOrientationIsLandscape(interfaceOrientation)); 
} 

Aquí está el código para presentar el controlador de vista que desea mostrar en el modo de paisaje:

FakeRootViewController* fakeRootViewController = [[FakeRootViewController alloc] init];[fakeRootViewController.navigationItem setBackBarButtonItem:backButton]; // Set back button 
// The parent navigation controller is the one containing the view controllers in portrait mode. 
fakeRootViewController.parentNavigationController = parentNavigationController; 

UINavigationController* subNavigationController = // Initialize this the same way you have initialized your parent navigation controller. 

UIViewController* landscapeViewController = // Initialize the landscape view controller 

[subNavigationController setViewControllers: 
    [NSArray arrayWithObjects:fakeRootViewController, 
               landscapeViewController, nil] animated:NO]; 

[_navigationController presentModalViewController:subNavigationController animated:YES]; 

Recuerde que el landscapeViewController también debe tener esta aplicación:

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    return (interfaceOrientation == UIInterfaceOrientationIsLandscape(interfaceOrientation)); 
} 
+1

+50 amazeballs. – Adam

+0

Finalmente una respuesta directa. – Jeef

0

Debe ser tan simple como la implementación de

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 

en cada UIViewController empujado en su UINavigationController. En el caso de que una vista de UIViewController no gire, return NO para esa orientación específica en ese específico UIViewController. Hay una Gotcha aquí, sin embargo, si su UINavigationController implementa

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 

que bloqueará sus viewControllers de recibir ese método. En ese caso, debe reenviar el mensaje al topViewController usando

[[self topViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation]; 
+3

Ojalá fuera así de simple. ¿Has probado eso? Hay algunos problemas con eso. 1. Si renderiza la vista de paisaje especial cuando el teléfono es vertical, cuando gira el teléfono a horizontal, la vista girará a vertical de forma inesperada. 2. cuando represente la vista especial del paisaje la primera vez, luego gire el teléfono hacia el retrato, luego salga de la vista especial y vuelva a ingresar, la vista se gira inesperadamente. Esto parece un problema con el controlador de navegación y realmente me gustaría que Apple pueda hacer que funcione para lo que describió. –

+0

Lo he intentado. Creo que los problemas que encuentras pueden ser específicos de tu aplicación. Intenta comenzar un nuevo proyecto para aislar el problema de rotación del UINavigationController, luego ejecuta algunos experimentos. – schellsan

0

Usted podría intentar este código en tu UINavigationController a la llamada de shouldAutorotateToInterfaceOrientation la vista visible actual. En mi caso tengo el UINavigationController en un UITabBarController pero probablemente puedas adaptarlo a otros casos.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    if ([appDelegate.tabBarController.selectedViewController respondsToSelector:@selector(topViewController)]) 
    { 
     UINavigationController *nc = (UINavigationController*)appDelegate.tabBarController.selectedViewController; 
     return [nc.topViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation]; 
    } 
    return (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 
0

Puede realizar acciones: cambiar su código con el acuerdo de la sugestión schellsan, al lado - Trate de añadir currentViewController (lo que empujará a la navegación viewController) como una propiedad que AppDelegate. Cuando intente empujar el controlador de vista, configúrelo en el controlador de vista actual antes de esto. A continuación, cree una subclase de rootViewController en el controlador de navegación. En este método SOBRECARGABLE subclase

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    // Overriden to allow any orientation. 
    return [appDelegate.currentViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation]; 
} 

Debería funciona si no se utiliza una barra de navegación y empuja nuevo controlador después de hacer estallar un antiguo controlador

+3

¿Cómo se logra lo mismo con la versión iOS 6? – Krishnan

1

Hay una API privada para forzar un cambio de orientación. Ponga en su controlador de vista empujado -viewWillAppear::

if ([UIDevice instancesRespondToSelector:@selector(setOrientation:)]) { 
    [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 
} 

Para suprimir la advertencia del compilador, agregar esto al archivo .m de su controlador de vista:

@interface UIDevice() 
- (void)setOrientation:(UIDeviceOrientation)orientation; // private API to let POIEntryVC be pushed over landscape route view 
@end 

Como siempre, hay un riesgo de ser rechazado y un riesgo de ruptura en futuras versiones del sistema operativo cuando se utilizan API privadas. ¡Hazlo bajo tu propio riesgo!

En general, la presentación de un controlador de vista modal es la mejor solución en la mayoría de los casos.

Cuestiones relacionadas