descargar - ios 12 cuando sale
Cómo forzar la orientación del controlador de vista en iOS 8? (24)
Mi solución
En AppDelegate
:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
if let topController = UIViewController.topMostViewController() {
if topController is XXViewController {
return [.Portrait, .LandscapeLeft]
}
}
return [.Portrait]
}
XXViewController
es ViewController que desea admitir el modo Paisaje.
Entonces la solución de Sunny Shah funcionaría en su XXViewController
en cualquier versión de iOS:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
Esta es la función de utilidad para encontrar ViewController superior.
extension UIViewController {
/// Returns the current application''s top most view controller.
public class func topMostViewController() -> UIViewController? {
let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
return self.topMostViewControllerOfViewController(rootViewController)
}
/// Returns the top most view controller from given view controller''s stack.
class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
// UITabBarController
if let tabBarController = viewController as? UITabBarController,
let selectedViewController = tabBarController.selectedViewController {
return self.topMostViewControllerOfViewController(selectedViewController)
}
// UINavigationController
if let navigationController = viewController as? UINavigationController,
let visibleViewController = navigationController.visibleViewController {
return self.topMostViewControllerOfViewController(visibleViewController)
}
// presented view controller
if let presentedViewController = viewController?.presentedViewController {
return self.topMostViewControllerOfViewController(presentedViewController)
}
// child view controller
for subview in viewController?.view?.subviews ?? [] {
if let childViewController = subview.nextResponder() as? UIViewController {
return self.topMostViewControllerOfViewController(childViewController)
}
}
return viewController
}
}
Antes de iOS 8, utilizamos el código siguiente junto con supportedInterfaceOrientations y debemos usar AutoRotate delegar métodos para forzar la orientación de la aplicación a cualquier orientación particular. Utilicé el siguiente fragmento de código para rotar la aplicación de forma programática según la orientación deseada. En primer lugar, estoy cambiando la orientación de la barra de estado. Y luego solo presentando y descartando de inmediato una vista modal gira la vista a la orientación deseada.
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
Pero esto está fallando en iOS 8. Además, he visto algunas respuestas en el desbordamiento de la pila donde las personas sugirieron que siempre debemos evitar este enfoque desde iOS 8 en adelante.
Para ser más específico, mi aplicación es un tipo de aplicación universal. Hay tres controladores en total.
Controlador First View : debe admitir todas las orientaciones del iPad y solo el retrato (botón de inicio inactivo) en iPhone.
Controlador de segunda vista : debe admitir solo paisaje correcto en todas las condiciones
Controlador de tercera vista : debe admitir solamente paisaje correcto en todas las condiciones
Estamos usando el controlador de navegación para la navegación de página. Desde el primer controlador de vista, en una acción de clic de botón, estamos presionando el segundo en la pila. Por lo tanto, cuando llega el segundo controlador de vista, independientemente de la orientación del dispositivo, la aplicación debe bloquearse solo en el paisaje.
A continuación se muestran mis métodos shouldAutorotate
y supportedInterfaceOrientations
en el segundo y tercer controlador de vista.
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeRight;
}
-(BOOL)shouldAutorotate {
return NO;
}
¿Hay alguna solución para esta o alguna otra forma mejor de bloquear un controlador de vista en una orientación particular para iOS 8. Por favor ayuda !!
Antes que nada, esta es una mala idea, en general, algo va mal con la arquitectura de tu aplicación, pero, sh..t happens
si es así, puedes intentar hacer algo como lo siguiente:
final class OrientationController {
static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]
// MARK: - Public
class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
OrientationController.allowedOrientation = [orientationIdiom]
}
class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
var mask:UIInterfaceOrientationMask = []
switch orientation {
case .unknown:
mask = [.all]
case .portrait:
mask = [.portrait]
case .portraitUpsideDown:
mask = [.portraitUpsideDown]
case .landscapeLeft:
mask = [.landscapeLeft]
case .landscapeRight:
mask = [.landscapeRight]
}
OrientationController.lockOrientation(mask)
UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
}
}
Que, en AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// do stuff
OrientationController.lockOrientation(.portrait)
return true
}
// MARK: - Orientation
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return OrientationController.allowedOrientation
}
Y cuando quiera cambiar de orientación, haga lo siguiente:
OrientationController.forceLockOrientation(.landscapeRight)
Nota: A veces, es posible que el dispositivo no se actualice de dicha llamada, por lo que es posible que deba hacer lo siguiente:
OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)
Eso es todo
De acuerdo con la respuesta de Korey Hinton
Swift 2.2:
extension UINavigationController {
public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return visibleViewController!.supportedInterfaceOrientations()
}
public override func shouldAutorotate() -> Bool {
return visibleViewController!.shouldAutorotate()
}
}
extension UITabBarController {
public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if let selected = selectedViewController {
return selected.supportedInterfaceOrientations()
}
return super.supportedInterfaceOrientations()
}
public override func shouldAutorotate() -> Bool {
if let selected = selectedViewController {
return selected.shouldAutorotate()
}
return super.shouldAutorotate()
}
}
Deshabilitar la rotación
override func shouldAutorotate() -> Bool {
return false
}
Bloquear a la orientación específica
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
De acuerdo con la solución mostrada por @sid-sha, tienes que poner todo en el método viewDidAppear:
contrario, no obtendrás la función didRotateFromInterfaceOrientation:
disparada, por lo que debes tener en didRotateFromInterfaceOrientation:
lo siguiente:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSNumber *value = [NSNumber numberWithInt:interfaceOrientation];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}
}
De esta manera me funciona en Swift 2 iOS 8.x:
PD (este método no requiere anular las funciones de orientación como debería realizar en cada viewController, solo un método en AppDelegate)
Verifique "requiere pantalla completa" en la información general del proyecto.
Por lo tanto, en AppDelegate.swift crea una variable:
var enableAllOrientation = false
Entonces, pon también esta función:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
if (enableAllOrientation == true){
return UIInterfaceOrientationMask.All
}
return UIInterfaceOrientationMask.Portrait
}
Entonces, en cada clase de tu proyecto puedes establecer esta var en viewWillAppear:
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.enableAllOrientation = true
}
Si necesita hacer una elección según el tipo de dispositivo, puede hacer esto:
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
switch UIDevice.currentDevice().userInterfaceIdiom {
case .Phone:
// It''s an iPhone
print(" - Only portrait mode to iPhone")
appDelegate.enableAllOrientation = false
case .Pad:
// It''s an iPad
print(" - All orientation mode enabled on iPad")
appDelegate.enableAllOrientation = true
case .Unspecified:
// Uh, oh! What could it be?
appDelegate.enableAllOrientation = false
}
}
Descubrí que si se trata de un controlador de vista presentado, puede anular la preferredInterfaceOrientationForPresentation
interfaz preferredInterfaceOrientationForPresentation
Rápido:
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return UIInterfaceOrientation.LandscapeLeft
}
override func shouldAutorotate() -> Bool {
return false
}
En Xcode 8
los métodos se convierten en propiedades, por lo que lo siguiente funciona con Swift
:
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.portrait
}
override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return UIInterfaceOrientation.portrait
}
override public var shouldAutorotate: Bool {
return true
}
Este es un comentario a los comentarios en la respuesta de Sid Shah , con respecto a cómo deshabilitar animaciones usando:
[UIView setAnimationsEnabled:enabled];
Código:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:NO];
[UIView setAnimationsEnabled:NO];
// #26357162 to force orientation
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:NO];
[UIView setAnimationsEnabled:YES];
}
Esto debería funcionar desde iOS 6 en adelante, pero solo lo he probado en iOS 8. Subclase UINavigationController
y anula los siguientes métodos:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
- (BOOL)shouldAutorotate {
return NO;
}
O pregunte al controlador de vista visible
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}
- (BOOL)shouldAutorotate {
return self.visibleViewController.shouldAutorotate;
}
e implementar los métodos allí.
Esto es lo que funcionó para mí:
Llámalo en tu método viewDidAppear:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[UIViewController attemptRotationToDeviceOrientation];
}
He intentado muchas soluciones, pero la que funcionó es la siguiente:
No es necesario editar el info.plist
en ios 8 y 9.
- (BOOL) shouldAutorotate {
return NO;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}
Posibles orientaciones de la documentación de Apple :
UIInterfaceOrientationDesconocido
La orientación del dispositivo no puede determinarse.
UIInterfaceOrientationPortrait
El dispositivo está en modo vertical, con el dispositivo en posición vertical y el botón de inicio en la parte inferior.
UIInterfaceOrientationPortraitUpsideDown
El dispositivo está en modo vertical pero boca abajo, con el dispositivo en posición vertical y el botón de inicio en la parte superior.
UIInterfaceOrientationLandscapeLeft
El dispositivo está en modo horizontal, con el dispositivo en posición vertical y el botón de inicio en el lado izquierdo.
UIInterfaceOrientationLandscapeRight
El dispositivo está en modo horizontal, con el dispositivo en posición vertical y el botón de inicio en el lado derecho.
Intenté algunas soluciones aquí y lo importante es comprender que es el controlador de vista raíz el que determinará si rotará o no.
github.com/GabLeRoux/RotationLockInTabbedViewChild el siguiente proyecto github.com/GabLeRoux/RotationLockInTabbedViewChild -c github.com/GabLeRoux/RotationLockInTabbedViewChild con un ejemplo funcional de un TabbedViewController
donde se TabbedViewController
que una vista secundaria gire y la otra vista secundaria se bloquea en vertical.
No es perfecto, pero funciona y la misma idea debería funcionar para otro tipo de vistas de raíz, como NavigationViewController
. :)
La combinación de las respuestas de Sids y Koreys funcionó para mí.
Extender el controlador de navegación:
extension UINavigationController {
public override func shouldAutorotate() -> Bool {
return visibleViewController.shouldAutorotate()
}
}
Luego deshabilitando la rotación en la única Vista
class ViewController: UIViewController {
override func shouldAutorotate() -> Bool {
return false
}
}
Y girando a la orientación adecuada antes de la transición
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SomeSegue")
{
let value = UIInterfaceOrientation.Portrait.rawValue;
UIDevice.currentDevice().setValue(value, forKey: "orientation")
}
}
La mejor solución de arriba:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
didnt''work para mí cuando lo llamé en viewDidAppear del controlador de vista presentado. Sin embargo, funcionó cuando lo llamé en preparForSegue en el controlador de vista de presentación.
(Lo sentimos, no hay suficientes puntos de reputación para comentar sobre esa solución, así que tuve que agregarlo así)
La rotación de orientación es un poco más complicada si se encuentra dentro de un UINavigationController
o UITabBarController
. El problema es que si un controlador de vista está incrustado en uno de estos controladores, el controlador de navegación o barra de pestañas tiene prioridad y toma las decisiones sobre la autorrotación y las orientaciones admitidas.
Utilizo las siguientes 2 extensiones en UINavigationController y UITabBarController para que los controladores de vista que están integrados en uno de estos controladores puedan tomar las decisiones.
¡Da a los controladores de vista el poder!
Swift 2.3
extension UINavigationController {
public override func supportedInterfaceOrientations() -> Int {
return visibleViewController.supportedInterfaceOrientations()
}
public override func shouldAutorotate() -> Bool {
return visibleViewController.shouldAutorotate()
}
}
extension UITabBarController {
public override func supportedInterfaceOrientations() -> Int {
if let selected = selectedViewController {
return selected.supportedInterfaceOrientations()
}
return super.supportedInterfaceOrientations()
}
public override func shouldAutorotate() -> Bool {
if let selected = selectedViewController {
return selected.shouldAutorotate()
}
return super.shouldAutorotate()
}
}
Swift 3
extension UINavigationController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
}
open override var shouldAutorotate: Bool {
return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
}
}
extension UITabBarController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let selected = selectedViewController {
return selected.supportedInterfaceOrientations
}
return super.supportedInterfaceOrientations
}
open override var shouldAutorotate: Bool {
if let selected = selectedViewController {
return selected.shouldAutorotate
}
return super.shouldAutorotate
}
}
Ahora puede anular el método supportedInterfaceOrientations
o puede anular shouldAutoRotate
en el controlador de vista que desea bloquear, de lo contrario puede omitir las anulaciones en otros controladores de vista que desea heredar el comportamiento de orientación predeterminado especificado en la lista de la aplicación
Deshabilitar la rotación
class ViewController: UIViewController {
override func shouldAutorotate() -> Bool {
return false
}
}
Bloquear a la orientación específica
class ViewController: UIViewController {
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}
}
En teoría, esto debería funcionar para todas las jerarquías de controlador de vista complejas, pero he notado un problema con UITabBarController. Por alguna razón, quiere usar un valor de orientación predeterminado. Consulte la siguiente publicación en el blog si está interesado en aprender cómo solucionar algunos de los problemas:
Mis requisitos son
- bloquear todas las vistas en modo vertical
- usa
AVPlayerViewController
para reproducir video
Cuando se reproduce el video, si se trata de un paisaje, entonces permite que la pantalla gire a la derecha paisaje y paisaje. Si se trata de un retrato, bloquee la vista en modo retrato solamente.
Primero, defina supportedInterfaceOrientationsForWindow
en AppDelegate.swift
var portrait = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
if portrait {
return .Portrait
} else {
return .Landscape
}
}
Segundo, en su controlador de vista principal, defina las siguientes funciones
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
print("/(#function)")
return .Portrait
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return .Portrait
}
override func shouldAutorotate() -> Bool {
return false
}
Entonces, debe subclasificar AVPlayerViewController
class MyPlayerViewController: AVPlayerViewController {
var size: CGSize?
var supportedOrientationMask: UIInterfaceOrientationMask?
var preferredOrientation: UIInterfaceOrientation?
override func viewDidLoad() {
super.viewDidLoad()
if let size = size {
if size.width > size.height {
self.supportedOrientationMask =[.LandscapeLeft,.LandscapeRight]
self.preferredOrientation =.LandscapeRight
} else {
self.supportedOrientationMask =.Portrait
self.preferredOrientation =.Portrait
}
}
}
Anule estas tres funciones en MyPlayerViewController.swift
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return self.supportedOrientationMask!
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return self.preferredOrientation!
}
Debido a que el usuario puede rotar el paisaje del dispositivo hacia la izquierda o hacia la derecha, tenemos que configurar la rotación automática para que sea verdadera
override func shouldAutorotate() -> Bool {
return true
}
Finalmente, cree MyPlayerViewController
instancia de MyPlayerViewController
en su controlador de vista y establezca el valor del tamaño de la propiedad.
let playerViewController = MyPlayerViewController()
// Get the thumbnail
let thumbnail = MyAlbumFileManager.sharedManager().getThumbnailFromMyVideoMedia(......)
let size = thumbnail?.size
playerViewController.size = size
Inicie su reproductor con el videoUrl
adecuado, luego asigne su reproductor a playerViewController
. Feliz codificación!
Para iOS 7 - 10:
C objetivo:
[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];
Swift 3:
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
Solo llámalo in - viewDidAppear:
del controlador de vista presentado.
Para mí, el VC de nivel superior necesitaba implementar las anulaciones de orientación. Usar VC abajo de la pila no tendrá efecto si el VC superior no está implementando.
VC-main
|
-> VC 2
|
-> VC 3
Solo VC-Main es escuchado, esencialmente en mi prueba.
Si está utilizando navigationViewController debe crear su propia superclase para esto y anular:
- (BOOL)shouldAutorotate {
id currentViewController = self.topViewController;
if ([currentViewController isKindOfClass:[SecondViewController class]])
return NO;
return YES;
}
esto desactivará la rotación en SecondViewController pero si empuja su SecondViewController cuando su dispositivo está en orientación vertical, entonces su SecondViewController aparecerá en modo vertical.
Suponga que está usando el guión gráfico. Debe crear un segue manual ( How to ) y en su método "onClick":
- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
[self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}
Esto forzará la orientación del paisaje antes de que su superclase deshabilite la característica de autorrotación.
Tengo el mismo problema y pierdo mucho tiempo para eso. Entonces ahora tengo mi solución. La configuración de mi aplicación solo es solo retrato de soporte. Sin embargo, algunas pantallas de mi aplicación deben tener solo paisaje. Lo arreglo por tener una variable isShouldRotate en AppDelegate . Y la función en AppDelegate :
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
if isShouldRotate == true {
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
Y finalmente, cuando un ViewControllerA necesita un estado de paisaje. Solo hazlo: antes de enviar / presentar a ViewControllerA assign isShouldRotate to true . No olvides cuando pop / dismiss que el controlador asigna isShouldRotate a false en viewWillDisappear .
Todavía parece haber cierto debate sobre la mejor manera de llevar a cabo esta tarea, así que pensé en compartir mi enfoque (de trabajo). Agregue el siguiente código en su implementación UIViewController
:
- (void) viewWillAppear:(BOOL)animated
{
[UIViewController attemptRotationToDeviceOrientation];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
-(BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft;
}
Para este ejemplo, también deberá establecer las orientaciones de su dispositivo permitido en ''Paisaje a la izquierda'' en la configuración de su proyecto (o directamente en info.plist
). Simplemente cambie la orientación específica que desea forzar si desea algo distinto de LandscapeLeft.
La clave para mí fue la llamada a viewWillAppear
en viewWillAppear
- sin eso, la vista no giraría correctamente sin girar físicamente el dispositivo.
Use esto para bloquear la orientación del controlador de vista, probado en IOS 9:
// Bloquear la orientación hacia el paisaje correcto
-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeRight;
}
-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
return UIInterfaceOrientationMaskLandscapeRight;
}
[iOS9 +] Si alguien arrastró todo el camino hasta aquí, ya que ninguna de las soluciones anteriores funcionó, y si presenta la vista que desea cambiar la orientación por segue, es posible que desee comprobar esto.
Verifique el tipo de presentación de su segue. El mío era ''sobre el contexto actual''. Cuando lo cambié a Pantalla completa, funcionó.
Gracias a @GabLeRoux, encontré esta solución.
- Este cambio solo funciona cuando se combina con las soluciones anteriores.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[UIViewController attemptRotationToDeviceOrientation];
}