¿Cómo permitir que solo un solo UIViewController gire en ambas direcciones horizontal y vertical?

Mi aplicación es solo para dispositivos iphone (ambos iPhone 4 y 5) y está diseñada para admitir solo ios 6 .

Toda mi aplicación solo es compatible con el modo portrait . Pero hay una vista llamada ” ChatView “, que quiero admitir modos de landscape y portrait .

He configurado las rotaciones de dispositivo requeridas de la siguiente manera:

enter image description here

También he intentado seguir el código para apoyar la rotación en “ChatView” –

 -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; } 

Pero no pudo rotar esa vista.

He buscado mucho para esto, pero no he podido encontrar la solución para mi problema.

Y también en “ChatView” hay algunos objetos como botones, campos de texto cuyos marcos están configurados programáticamente. Entonces, ¿quiero saber si debo establecer marcos de todos esos objetos para el modo horizontal también?

Por favor, ayúdame.

Gracias…..

Creo que si desea admitir solo una rotación de viewcontroller, no es posible ya que la aplicación seguirá las orientaciones establecidas por usted en el archivo .plist . Una alternativa que puede seguir es la de admitir su aplicación para el paisaje y el retrato, congelar todos los controles de view rotation a portrait, excepto la vista de chat.

EDITAR

Para subclase UINavigationController , cree un nuevo archivo con el nombre, por ejemplo, CustomNavigationController y UINavigationController en la subclase de UINavigationController .

archivo .h

 #import  @interface CustomNavigationController : UINavigationController @end 

archivo .m

 #import "CustomNavigationController.h" @interface CustomNavigationController () @end @implementation CustomNavigationController -(BOOL)shouldAutorotate { return NO; } -(UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return UIInterfaceOrientationIsPortrait(interfaceOrientation); } @end 

Establezca la clase de su UINavigationController en su clase principal xib como CustomNavigationController . Espero que ayude ypu ..

Simple pero funciona muy bien. IOS 7.1 y 8

AppDelegate.h

 @property () BOOL restrictRotation; 

AppDelegate.m

 -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { if(self.restrictRotation) return UIInterfaceOrientationMaskPortrait; else return UIInterfaceOrientationMaskAll; } 

ViewController

 -(void) restrictRotation:(BOOL) restriction { AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate; appDelegate.restrictRotation = restriction; } 

viewDidLoad

 [self restrictRotation:YES]; or NO 

Su controlador de vista nunca girará a ninguna posición que no sea compatible con la aplicación en sí. Debe habilitar todas las rotaciones posibles y luego, en los controladores de vista que no deben rotar, coloque las siguientes líneas

 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 

En ChatView, debería ser:

 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } 

Si necesita cambiar su diseño después de una rotación, debe implementar los cambios apropiados en sus subvistas en

 - (void)viewWillLayoutSubviews 

Utilice self.view.bounds para verificar el tamaño actual de la view , ya que self.view.frame no cambia después de las rotaciones.

para el viewcontroller.m específico que desea rotar

agrega este método:

 - (BOOL)canAutoRotate { return YES; } 

luego dentro de su AppDelegate.m

 - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { UIViewController *currentViewController = [self topViewController]; if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) { NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setSelector:@selector(canAutoRotate)]; [invocation setTarget:currentViewController]; [invocation invoke]; BOOL canAutorotate = NO; [invocation getReturnValue:&canAutorotate]; if (canAutorotate) { return UIInterfaceOrientationMaskAll; } } return UIInterfaceOrientationMaskPortrait; } - (UIViewController *)topViewController { return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } - (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController { if ([rootViewController isKindOfClass:[UITabBarController class]]) { UITabBarController* tabBarController = (UITabBarController*)rootViewController; return [self topViewControllerWithRootViewController:tabBarController.selectedViewController]; } else if ([rootViewController isKindOfClass:[UINavigationController class]]) { UINavigationController* navigationController = (UINavigationController*)rootViewController; return [self topViewControllerWithRootViewController:navigationController.visibleViewController]; } else if (rootViewController.presentedViewController) { UIViewController* presentedViewController = rootViewController.presentedViewController; return [self topViewControllerWithRootViewController:presentedViewController]; } else { return rootViewController; } } 

La respuesta de Ted funciona bien con el problema mencionado por Alexander de Noruega. Pero pensé que el problema no estaba sucediendo de la manera que Alexander explicó,

Cuando ViewController B, que actualmente está en el modo paisaje (todas las orientaciones habilitadas) regresa a ViewController A. (solo retrato) después de que el usuario hace clic en el botón Atrás, supportedInterfaceOrientationsForWindow no recibe una llamada y ViewController A termina en paisaje

En realidad, cuando ViewController B, que actualmente está en el paisaje (todas las orientaciones habilitadas) regresa a ViewController A (solo retrato) después de que el usuario hace clic en el botón Atrás, Appdelegate

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; 

está siendo llamado. Pero aún el controlador de vista raíz es ViewController B (ese controlador de vista habilitado para la rotación), ViewController A no está volviendo a la orientación vertical, ya que ViewController B todavía está regresando

 -(BOOL)shouldAutorotate{ return YES; } 

Entonces, cuando presiona el botón Atrás, “shouldAutorotate -> NO” en ViewController B. Entonces ViewController A llegará a la orientación vertical. Esto es lo que hice

 @property (nonatomic, assign) BOOL canAutoRotate; #pragma mark - Public methods - (BOOL)canAutoRotate { return _canAutoRotate; } #pragma mark - Button actions - (void)backButtonPressed:(UIButton *)sender { _canAutoRotate = NO; (...) } #pragma mark - Init - (id)init{ if(self=[super init]) { _canAutoRotate = YES; } return self; } 

En función de la respuesta de @ iAnum, habilité la detección de autorrotación y la clase UIViewController.

Esto se debe a que, de lo contrario, la transición hacia y desde el “controlador de vista especial” no se corregirá a la orientación vertical, y se encontrará atascado en una orientación no compatible.

Solo tenía una vista compatible con el paisaje, así que solo lo codifiqué en el controlador de vista de navegación personalizado:

 -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { //Access the current top object. UIViewController *viewController = [self.viewControllers lastObject]; //Is it one of the landscape supported ones? if ([viewController isMemberOfClass:[SpecialViewController class]]) { return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; } else return UIInterfaceOrientationMaskPortrait; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { //Access the current top object. UIViewController *viewController = [self.viewControllers lastObject]; //Is it one of the landscape supported ones? if ([viewController isMemberOfClass:[SpecialViewController class]]) { return interfaceOrientation; } else return UIInterfaceOrientationIsPortrait(interfaceOrientation); } 

Hay un problema apareciendo VCs discutidos aquí https://stackoverflow.com/a/15057537/1277350 donde presionar hacia atrás mientras está en el paisaje ni siquiera llamará a los métodos de orientación, por lo que tiene que hackearlo un poco mostrando y descartando un vista modal.

Y recuerde que si desea que willShowViewController se active, debe establecer self.delegate = self y agregar UINavigationControllerDelegate a su controlador de navegación personalizado junto con el código siguiente.

 - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return UIInterfaceOrientationPortrait; } - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { UIApplication* application = [UIApplication sharedApplication]; if (application.statusBarOrientation != UIInterfaceOrientationPortrait) { UIViewController *c = [[UIViewController alloc]init]; [c.view setBackgroundColor:[UIColor clearColor]]; [navigationController presentViewController:c animated:NO completion:^{ [self dismissViewControllerAnimated:YES completion:^{ }]; }]; } } 

crea una subclase de UINavigationController así:

MyNavigationController.h

 #import  @interface MyNavigationController : UINavigationController @end 

MyNavigationController.m

 #import "MyNavigationController.h" #import "ServicesVC.h" @implementation MyNavigationController -(BOOL)shouldAutorotate{ return YES; } -(NSUInteger)supportedInterfaceOrientations{ if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) { return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; } return UIInterfaceOrientationMaskAll; } @end 

suponiendo que su viewcontroller se llama: ServicesVC

Aquí está la respuesta de Alexander ( https://stackoverflow.com/posts/25507963/revisions ) en Swift:

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int { var currentViewController: UIViewController? = self.topViewController() if currentViewController != nil && currentViewController!.canAutoRotate() { return Int(UIInterfaceOrientationMask.All.rawValue) } return Int(UIInterfaceOrientationMask.Portrait.rawValue) } func topViewController() -> UIViewController? { if UIApplication.sharedApplication().keyWindow != nil { return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!) } return nil } func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? { if rootViewController == nil { return nil } if rootViewController!.isKindOfClass(UITabBarController) { var tabBarController: UITabBarController = (rootViewController as? UITabBarController)! return self.topViewControllerWithRootViewController(tabBarController.selectedViewController) } else { if rootViewController!.isKindOfClass(UINavigationController) { var navigationController: UINavigationController = (rootViewController as? UINavigationController)! return self.topViewControllerWithRootViewController(navigationController.visibleViewController) } else { if (rootViewController!.presentedViewController != nil) { var presentedViewController: UIViewController = rootViewController!.presentedViewController! return self.topViewControllerWithRootViewController(presentedViewController) } else { return rootViewController } } } } 

Además, deberá agregar el siguiente fragmento en AppDelegate.swift:

 extension UIViewController { func canAutoRotate() -> Bool { return false }} 

Y para ViewControllers para los que desea permitir todas las rotaciones, agregue esta función:

 override func canAutoRotate() -> Bool { return true } 

No estoy seguro de la historia de este problema (ahora = intervalo de tiempo de iOS 10), pero me faltaba la solución más fácil porque publiqué esto en octubre de 2016.

Suponiendo que quieras esto:

  1. Compatibilidad con iOS 7 y versiones posteriores solamente (incluido iOS 10)
  2. Algunos controladores de vista deben admitir todas las orientaciones, otros deben admitir un subconjunto de orientaciones. Ejemplo de lo que quiero decir: un controlador de vista solo debería admitir retrato, mientras que todos los demás deberían ser compatibles con todas las orientaciones
  3. Todos los controladores de vista deben rotar automáticamente si admiten la rotación (es decir, no desea que el código que corrige este problema se encuentre en los controladores de visualización)
  4. Admite agregar UINavigationController en XIB / NIB / Storyboards sin tener que hacer nada con ellos

… entonces (IMO) la solución más fácil es hacer un UINavigationControllerDelegate , NO subclase UINavigationController (que infringe la suposición 4 anterior).

Cuando resolví esto, decidí convertir mi primer ViewController en UINavigationControllerDelegate . Este controlador de vista se establece como el delegado del controlador de navegación y devuelve las orientaciones permitidas. En mi caso, el valor predeterminado es que se permiten todas las orientaciones, con el retrato preferido, pero en un caso particular solo se permite el retrato. El siguiente código es de Swift 3 / XCode 8:

  class iPhoneStartViewController: UIViewController { var navInterfaceOrientationMask: UIInterfaceOrientationMask? var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait override func viewDidLoad() { super.viewDidLoad() self.navigationController?.delegate = self } @IBAction func cameraButtonPressed(_ sender: AnyObject) { if PermissionsHelper.singleton().photosPermissionGranted() == false { self.navInterfaceOrientationMask = nil // default is: all orientations supported self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self) } else { self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait self.performSegue(withIdentifier: "segueToCamera", sender: self) } } } // lock orientation to portrait in certain cases only. Default is: all orientations supported extension iPhoneStartViewController : UINavigationControllerDelegate { public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask { if let mask = self.navInterfaceOrientationMask { return mask } else { return .all } } public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation { return self.navInterfaceOrientationPreferred } } 

Swift 3 Kosher Version

Lo dejé aquí solo por un caso que alguien tiene el problema.

La documentación de Apple para supportedInterfaceOrientations dice:

Cuando el usuario cambia la orientación del dispositivo, el sistema llama a este método en el controlador de vista raíz o al controlador de vista presentado más arriba que llena la ventana. Si el controlador de vista admite la nueva orientación, la ventana y el controlador de vista se rotan a la nueva orientación. Este método solo se invoca si el método shouldAutorotate del controlador de vista devuelve verdadero.

En pocas palabras, debe sobrescribir supportedInterfaceOrientations en el controlador de vista raíz para que devuelva el valor para su controlador de vista secundaria superior y el valor predeterminado de lo contrario.

Entonces, lo que debe hacer es verificar si la aplicación admite todos los modos (vaya a Información de implementación en la configuración general de los objectives o Info.plist), descubra la clase de su controlador de vista raíz. Puede ser UIViewController genérico, UINavigationController, UITabBarController o alguna clase personalizada. Puede verificarlo, por ejemplo, de esta manera:

 dump(UIApplication.shared.keyWindow?.rootViewController) 

O de cualquier otra forma que te guste

Deja que sea un CustomNavigationController . Por lo tanto, debe anular las supportedInterfaceOrientations interfaz supportedInterfaceOrientations esta manera:

 class CustomNavigationController: UINavigationController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown } } 

En cualquier controlador de vista que solo debería admitir la orientación vertical, por ejemplo, anule las orientaciones de interfaz supportedInterfaceOrientations esta manera:

 class ChildViewController: UIViewController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } } 

Entonces no te olvides de verificar si shouldAutorotate tu controlador de vista raíz y el controlador de vista presentado más arriba ya devuelve true . Si no, agregue esto a las definiciones de las clases:

 override var shouldAutorotate: Bool { return true } 

De lo contrario, no se llamará en modo alguno a InterferirOrientations.

¡Aqui tienes!

Si necesita solucionar el problema opuesto cuando solo un controlador de vista debe admitir un grupo de orientaciones y otras no, haga que esto cambie a cada controlador de vista excepto a este.

Espero que esto ayude

Tuve la misma situación. Así que clasifiqué UINavigationController en CustomNavigationController, y dentro de este CustomNavigationController, escribí

 #define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 ) #define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 ) #pragma mark - Rotation #ifdef IOS_OLDER_THAN_6 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return (toInterfaceOrientation == UIInterfaceOrientationPortrait); } #endif #ifdef IOS_NEWER_OR_EQUAL_TO_6 -(BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait;; } #endif 

Usé este CustomNavigationController en lugar del NavigationController existente.

Luego, dentro del controlador de vista que tienes que mostrar en LandScape Orientation di LandScapeView, escribí

 #pragma mark - Rotation #ifdef IOS_OLDER_THAN_6 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft); } #endif #ifdef IOS_NEWER_OR_EQUAL_TO_6 -(BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft; } #endif 

Dentro de CustomNavigationController, presenté este controlador de vista, no insertado en la stack de navegación. Entonces LandScapeView apareció en LandScape Orientation.

 LandScapeView *graph = [[LandScapeView alloc]init....]; [self presentViewController:graph animated:YES completion:nil]; 

No cambié nada en la Orientación de interfaz admitida en Configuración del proyecto.

// pegar este método en la clase deligate de la aplicación

 - (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window { if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]]) { if (self.window.rootViewController.presentedViewController) return UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait; } else return UIInterfaceOrientationMaskPortrait; } 

Si la aplicación es compatible desde IOS7 a IOS9, use este código para Orientación:

 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000 - (NSUInteger)supportedInterfaceOrientations #else - (UIInterfaceOrientationMask)supportedInterfaceOrientations #endif { if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; } 

Sé que esta pregunta es muy antigua, pero necesita una respuesta actualizada. La manera más fácil y correcta de lograr este resultado es habilitar Vertical y Horizontal en la configuración de su aplicación. A continuación, agregue este código al delegado de su aplicación:

  func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask { if let navigationController = self.window?.rootViewController as? UINavigationController { if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE { return UIInterfaceOrientationMask.All } else { return UIInterfaceOrientationMask.Portrait } } return UIInterfaceOrientationMask.Portrait } 

No olvide reemplazar “INSERTYOURVIEWCONTROLLERHERE” con su controlador de vista.