ios iphone uiviewcontroller swift screen-rotation

ios - ¿Cómo mantener la orientación del controlador de vista de presentación al descartar el controlador de vista modal?



iphone uiviewcontroller (9)

Tengo esta aplicación en la que estoy trabajando y necesito TODOS mis controladores de vista, pero uno para estar en vertical. El único controlador de vista que es especial lo necesito para poder girar a cualquier orientación en la que se encuentre el teléfono.

Para hacer eso lo presento modalmente (no incrustado en un NavigationController)

Entonces (por ejemplo) mi estructura es así:

  • ventana - retrato
    • Controlador de vista raíz (UINavigationController - Retrato)
      • Controlador de vista del hogar (UIViewController - Retrato)
        • Controlador de vista de detalles (UIViewController - Retrato)
        • .
        • .
        • .
        • controlador de vista modal (UIVIewController - Todos)

Ahora, cuando descarto mi controlador de vista modal en una posición horizontal, mi controlador de vista principal TAMBIÉN está girado aunque no admita esa orientación.

Todos los UIViewControllers y UINavigaionControllers en la aplicación heredan de las mismas clases generales que tienen estos métodos implementados:

override func supportedInterfaceOrientations() -> Int { return Int(UIInterfaceOrientationMask.Portrait.toRaw()) }

Mi controlador de vista modal anula este método una vez más y se ve así:

override func supportedInterfaceOrientations() -> Int { return Int(UIInterfaceOrientationMask.All.toRaw()) }

Actualización 1

Parece que esto está sucediendo solo en iOS8 Beta. ¿Alguien sabe si hay algo que cambió con respecto a la rotación del controlador de vista o es solo un error en la versión beta?


Swift 3.0 O Arriba, Simplemente verifique la propiedad "isBeingDismissed" del controlador de vista presentado. A continuación se muestra el código de ejemplo. Esta función girará el controlador de vista de presentación al modo retrato inmediatamente después de que se cierre el controlador de vista de presentación.

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) { if rootViewController.canRotateVC == true { if baseVC.isBeingDismissed == false { return .allButUpsideDown } } } return .portrait}

Puede obtener topController por el siguiente código:

private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController?{ if (rootViewController == nil) { return nil }if (rootViewController.isKind(of: (UITabBarController).self)) { return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController) } else if (rootViewController.isKind(of:(UINavigationController).self)) { return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController) } else if (rootViewController.presentedViewController != nil) { return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController) } return rootViewController }


Después de mucha experimentación, estoy convencido de que esta es una "característica" de iOS 8.

Si lo piensas bien, esto tiene mucho sentido, ya que ha estado viniendo durante mucho tiempo.

  • En, digamos, iOS 4, fue posible forzar la rotación de la aplicación al cambiar los controladores de vista en un controlador de barra de pestañas y un controlador de navegación, así como al presentar / descartar un controlador.

  • Luego, en iOS 6 se hizo imposible forzar la rotación de aplicaciones, excepto al presentar / descartar un controlador de vista (como expliqué en muchas respuestas, como esta ).

  • Ahora, en iOS 8, supongo que será imposible forzar la rotación de aplicaciones (excepto en el lanzamiento). Puede preferir una cierta orientación, de modo que una vez que esté en esa orientación, permanecerá allí, pero no puede obligar a la aplicación a entrar en esa orientación.

    En cambio, se espera que su controlador de vista se "adapte". Hay varios videos de la WWDC 2014 concentrados en la "adaptación", y ahora estoy empezando a entender que esta es una de las razones por las que esto es tan importante.

    EDITAR: ¡ En la semilla 4, parece que esta característica (forzando la rotación en la presentación y el despido) está regresando!


En el controlador de vista raíz, intente agregar:

- (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; }

Trabajó para mi.


Esto es realmente más fácil y se puede hacer sin ninguna propiedad adicional (aquí hay un ejemplo con AVPlayerViewController ):

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { if ([self.window.rootViewController.presentedViewController isKindOfClass: [AVPlayerViewController class]]) return self.window.rootViewController.presentedViewController.isBeingDismissed ? UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait; } else { return UIInterfaceOrientationMaskAll; } }


Pregunta asombrosa y respuesta asombrosa proporcionada por @ZaEeM ZaFaR ! Combinar su respuesta con this me llevó a una gran solución más genérica.

El inconveniente de la primera respuesta es que debe administrar la variable isPresented en cada controlador de vista que permita rotaciones. Además, tiene que expandir la comprobación y convertir en supportedInterfaceOrientationsForWindow para cada vc que permita la rotación.

El inconveniente de la segunda respuesta es que no funciona; también rota la presentación vc cuando se desecha la presentación vc.

Esta solución permite la rotación en todos los vc donde se coloca canRotate () {} y no gira el vc actual.

Swift 3:
En AppDelegate.swift:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) { if (rootViewController.responds(to: Selector(("canRotate")))) { // Unlock landscape view orientations for this view controller if it is not currently being dismissed if !rootViewController.isBeingDismissed{ return .allButUpsideDown } } } // Only allow portrait (standard behaviour) return .portrait } private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? { if (rootViewController == nil) { return nil } if (rootViewController.isKind(of: UITabBarController.self)) { return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController) } else if (rootViewController.isKind(of: UINavigationController.self)) { return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController) } else if (rootViewController.presentedViewController != nil) { return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController) } return rootViewController }

En cada vista controlador donde se debe permitir la rotación:

func canRotate(){}


Tenemos una aplicación implementada que tiene un controlador de paisaje que presenta un controlador de vista solo de retrato. Fue revisado por Apple en iOS 8. Solo estamos anulando las Interorientación OrientadaOrientaciones.

Vale la pena señalar que encontramos muchas diferencias entre las versiones Beta 3,4 y 5. Al final, tuvimos que esperar al GM antes de hacer un esfuerzo concertado para actualizar nuestra aplicación para iOS 8.

Debes tener mucho cuidado en iOS 8 para asegurarte de no hacer esto:

[self dismissViewControllerAnimated:YES completion:nil] [self presentViewController:vc animated:YES completion:nil]

Si el vc saliente es vertical, y el entrante es horizontal, algunos marcos de vista pueden terminar muy desordenados. Presente el vc entrante en el bloque de finalización de la llamada de despedida en su lugar.

[self dismissViewControllerAnimated:YES completion:^{ [self presentViewController:vc animated:YES completion:nil] }];


Tengo el mismo problema con una aplicación y después de días de experimentación se me ocurrió una solución que no es muy buena pero que funciona por ahora. Estoy usando la application:supportedInterfaceOrientationsForWindow: método delegado application:supportedInterfaceOrientationsForWindow: supportInterfaceOrientationsForWindow application:supportedInterfaceOrientationsForWindow: dentro del appdelegate.

Creé un proyecto de prueba y lo puse aquí en github (incluido un GIF que muestra el resultado ...)

// nota: no es rápido pero espero que ayude de todos modos



- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]]) { SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController; if (secondController.isPresented) return UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait; } else return UIInterfaceOrientationMaskPortrait; }

Y para Swift

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int { if self.window?.rootViewController?.presentedViewController? is SecondViewController { let secondController = self.window!.rootViewController.presentedViewController as SecondViewController if secondController.isPresented { return Int(UIInterfaceOrientationMask.All.toRaw()); } else { return Int(UIInterfaceOrientationMask.Portrait.toRaw()); } } else { return Int(UIInterfaceOrientationMask.Portrait.toRaw()); } }

Para más detalles revisa este link