Orientación en una UIView agregada a una UIWindow

Tengo una UIView que se supone que cubre todo el dispositivo (UIWindow) para admitir un efecto de acercamiento / alejamiento de imagen que estoy haciendo usando la animación central donde un usuario toca un botón en una UITableViewCell y hago zoom en la imagen asociada.

El zoom está funcionando impecablemente, lo que no he podido descifrar es por qué la subvista todavía está en modo vertical a pesar de que el dispositivo está en el paisaje. Una ilustración a continuación:

enter image description here

Tengo un controlador de navegación, pero esta vista se ha agregado a la ventana UI directamente.

Puede leer sobre algunas de las posibles causas aquí:
Preguntas y respuestas técnicas QA1688: ¿Por qué mi UIViewController no girará con el dispositivo?

En su situación, es probable que esté agregando la vista como otra subvista a la ventana. Solo la primera subvista obtiene los eventos de rotación. Lo que puede hacer es agregarlo como una subvista de la primera subvista de la ventana.

UIWindow* window = [UIApplication sharedApplication].keyWindow; if (!window) window = [[UIApplication sharedApplication].windows objectAtIndex:0]; [[[window subviews] objectAtIndex:0] addSubview:myView]; 

El problema

A partir de iOS 6, solo el controlador de vista superior (junto con el objeto UIApplication) participa en la decisión de rotar en respuesta a un cambio en la orientación del dispositivo.

https://developer.apple.com/library/content/qa/qa1688/_index.html

La solución

He abierto una fuente llamada AGWindowView .
Automáticamente se ocupará de cualquier rotación y cambios de cuadro, por lo que no tendrá que preocuparse por eso.

El código

Admite cualquier combinación de versiones de sistema iOS y SDK. El código relevante se puede encontrar aquí: https://github.com/hfossli/AGWindowView/blob/master/Source/AGWindowView.m

Creé una categoría en UIApplication que tiene una propiedad de ayuda y un método para obtener la primera subvista de la ventana clave. Esta es la vista que desea superponer de todos modos. Ahora cuando agrega una vista que es administrada por un UIViewController a esa vista, se llama al método shouldRotateToInterfaceOrientation :.

UIApplication + WindowOverlay.h

 #import  @interface UIApplication(WindowOverlay) @property (nonatomic, readonly) UIView *baseWindowView; -(void)addWindowOverlay:(UIView *)view; @end 

UIApplication + WindowOverlay.m

 #import "UIApplication+WindowOverlay.h" @implementation UIApplication(WindowOverlay) -(UIView *)baseWindowView{ if (self.keyWindow.subviews.count > 0){ return [self.keyWindow.subviews objectAtIndex:0]; } return nil; } -(void)addWindowOverlay:(UIView *)view{ [self.baseWindowView addSubview:view]; } @end 

y así es como lo usarías.

 //at the top of the file...or in {yourproject}.pch #import "UIApplication+WindowOverlay.h //in a method: UIView *view = [UIView new]; UIView *window = [UIApplication sharedApplication].baseWindowView; view.frame = window.bounds; [window addSubview:view]; //or [[UIApplication sharedApplication] addWindowOverlay:view]; 

Esto se debe a que, como mencionas, tu vista se ha agregado directamente a la ventana UI, por lo tanto, cuando se llama al método de rotación para el controlador de navegación, no sucede nada con la vista. La UIView rotaría si fuera una subvista de la vista del controlador de vista. Si por alguna razón esto no puede hacerse. Entonces podrías anular este método:

 // This method is called every time the device changes orientation - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations } 

Y cada vez que cambie su orientación, también cambiará su orientación visual.

Tuve un problema similar con las vistas que se agregan directamente a una ventana. Tal vez esto ayude: dimensionar automáticamente UIView después de agregar a la ventana

Otra solución es cómo resolví este problema.

Definir la Orientación actual:

 @interface AJImageCollectionViewController (){ UIInterfaceOrientation _currentOrientation; } @end 

Luego verifique la orientación en viewWillLayoutSubviews:

 - (void)viewWillLayoutSubviews { [self checkIfOrientationChanged]; } - (void)checkIfOrientationChanged { UIInterfaceOrientation newOrientation = [[UIApplication sharedApplication] statusBarOrientation]; BOOL newOrientationIsPortrait = UIInterfaceOrientationIsPortrait(newOrientation); BOOL oldOrientationIsPortrait = UIInterfaceOrientationIsPortrait(_currentOrientation); // Check if the orientation is the same as the current if(newOrientationIsPortrait != oldOrientationIsPortrait){ _currentOrientation = newOrientation; // Do some stuff with the new orientation } }