iphone - fotos - iOS 6: ¿Cómo restrinjo algunas vistas al retrato y a otras personas para que giren?
ios fotos personas (15)
Agregar un Controlador de navegación personalizado
Anular estos métodos en él:
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
Ahora agregue todas las orientaciones en el plist
En el controlador de vista, agregue solo los obligatorios:
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
estos métodos anulan los métodos del controlador de navegación
Tengo una aplicación para iPhone que usa un UINavigationController
para presentar una interfaz de exploración: primero una vista, luego otra, hasta cuatro niveles de profundidad. Quiero que las primeras tres vistas estén restringidas a la orientación vertical y solo la última vista debe rotar a horizontal. Cuando regrese de la cuarta vista a la tercera y la cuarta vista esté en orientación horizontal, quiero que todo gire de nuevo a vertical.
En iOS 5 simplemente shouldAutorotateToInterfaceOrientation:
en cada uno de mis controladores de vista para devolver SÍ para las orientaciones permitidas. Todo funcionó como se describió anteriormente, incluido el retorno al retrato incluso si el dispositivo se mantenía en orientación horizontal cuando regresaba del controlador de visualización n. ° 4 a n. ° 3.
En iOS 6, todos los controladores de vista giran al paisaje, rompiendo aquellos que no estaban destinados a hacerlo. Las notas de la versión iOS 6 dicen
Se está transfiriendo más responsabilidad a la aplicación y a la aplicación delegada. Ahora, los contenedores iOS (como
UINavigationController
) no consultan a sus hijos para determinar si deben autorrotar. [...] El sistema le pide al controlador de vista de pantalla completa superior (generalmente el controlador de vista raíz) sus orientaciones de interfaz compatibles cada vez que el dispositivo gira o cada vez que se presenta un controlador de vista con el estilo de presentación modal de pantalla completa. Además, las orientaciones admitidas se recuperan solo si este controlador de vista devuelve SÍ de su métodoshouldAutorotate
. [...] El sistema determina si se admite una orientación al intersectar el valor devuelto por el métodosupportedInterfaceOrientationsForWindow:
con el valor devuelto por el métodosupportedInterfaceOrientations
del controlador de pantalla completa superior.
Así que UINavigationController
, le di a MainNavigationController
una propiedad booleana landscapeOK
y la usé para devolver las orientaciones permitidas en supportedInterfaceOrientations
. Luego, en cada uno de los controladores de mi vista viewWillAppear:
methods tengo una línea como esta
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
para decirle a MainNavigationController
el comportamiento deseado.
Aquí viene la pregunta: si ahora navego a mi cuarta vista en modo retrato y giro el teléfono sobre él, gira a horizontal. Ahora presiono el botón Atrás para regresar a mi tercera vista, que se supone que funciona solo como retrato. Pero no gira hacia atrás. ¿Cómo hago para que haga eso?
Lo intenté
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]
en el método viewWillAppear
de mi tercer controlador de vista, pero no hace nada. ¿Es este el método incorrecto para llamar o tal vez el lugar equivocado para llamarlo o debería implementarlo todo de una manera totalmente diferente?
Desea forzar el retrato de la aplicación iOS 6 solo luego puede agregar a una subclase UIViewController debajo de los métodos
- (BOOL)shouldAutorotate {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return YES;
} else {
return NO;
}
}
- (NSUInteger)supportedInterfaceOrientations {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
Después de ver todas las respuestas en innumerables preguntas similares en SO, ninguna de las respuestas funcionó para mí, pero sí me dieron algunas ideas. Así es como terminé resolviendo el problema:
Primero, asegúrese de que las orientaciones de interfaz admitidas en el objetivo de su proyecto contengan todas las orientaciones que desee para su vista rotativa.
A continuación, UINavigationController
una categoría de UINavigationController
(ya que Apple dice que no la subclases):
@implementation UINavigationController (iOS6AutorotationFix)
-(BOOL)shouldAutorotate {
return [self.topViewController shouldAutorotate];
}
@end
Importe esa categoría y el controlador de vista que desea rotar (que llamaré a RotatingViewController
) a su controlador de vista de nivel más alto, que debe contener su controlador de navegación. En ese controlador de vista, implemente shouldAutorotate
siguiente manera. Tenga en cuenta que este no debe ser el mismo controlador de vista que desea rotar.
-(BOOL)shouldAutorotate {
BOOL shouldRotate = NO;
if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) {
shouldRotate = [navigationController.topViewController shouldAutorotate];
}
return shouldRotate;
}
Finalmente, en su shouldAutorotate
RotatingViewController
shouldAutorotate
, implemente shouldAutorotate
y supportedInterfaceOrientations
siguiente manera:
-(BOOL)shouldAutorotate {
// Preparations to rotate view go here
return YES;
}
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate
}
La razón por la que necesita hacer esto es porque iOS 6 le da control de rotación al controlador de vista raíz en lugar del control de vista superior. Si desea que la rotación de una vista individual se comporte de manera diferente que otras vistas en la pila, debe escribir un caso específico para ella en el controlador de la vista raíz.
Esto es lo que estoy usando para orientación en ios 6.0
-(BOOL)shouldAutorotate{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
Esto podría no funcionar para todos, pero funciona muy bien para mí. En lugar de implementar ...
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
en vista de aparecer en todos mis controladores, decidí centralizar este proceso dentro de mi subclase UINavigationController anulando el método UINavigationControllerDelegate navigationController:willShowViewController:animated:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
self.previousVCLandscapeOK = self.isLandscapeOK; // Store the current VC''s orientation preference before pushing on the new VC so we can set this again from within the custom "back" method
self.isLandscapeOK = NO; // Set NO as default for all VC''s
if ([viewController isKindOfClass:[YourViewController class]]) {
self.isLandscapeOK = YES;
}
}
Descubrí que este método de delegado no se llama cuando se saca un VC de la pila de navegación. Esto no fue un problema para mí porque estoy manejando la funcionalidad de respaldo desde mi subclase UINavigationController para poder establecer los botones y acciones de la barra de navegación adecuados para VC específicos como este ...
if ([viewController isKindOfClass:[ShareViewController class]]) {
UIButton* backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 57, 30)];
[backButton setImage:[UIImage imageNamed:@"back-arrow"] forState:UIControlStateNormal];
[backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
viewController.navigationItem.leftBarButtonItem = backButtonItem;
UIImageView* shareTitle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"share-title"]];
[shareTitle setContentMode:UIViewContentModeScaleAspectFit];
[shareTitle setFrame:CGRectMake(0, 0, shareTitle.frame.size.width - 10, shareTitle.frame.size.height - 10)];
viewController.navigationItem.titleView = shareTitle;
} else if(...) {
...
}
Aquí está el aspecto de mi método de back
para sacar el VC de la pila y establecer la preferencia de rotación adecuada ...
- (void)back {
self.isLandscapeOK = self.previousVCLandscapeOK;
self.previousVCLandscapeOK = NO;
[self popViewControllerAnimated:YES];
}
Entonces, como pueden ver, básicamente todo lo que está sucediendo es que primero estoy estableciendo dos propiedades ...
@property (nonatomic) BOOL isLandscapeOK;
@property (nonatomic) BOOL previousVCLandscapeOK;
en navigationController:willShowViewController:animated:
que determinará cuáles son las orientaciones admitidas dentro de ese VC que está a punto de presentarse. Cuando aparece un VC, se llama a mi método personalizado "back" y luego estoy configurando el isLandscapeOK a lo que se almacenó mediante el valor anterior de VCLandscapeOK.
Como dije, esto podría no funcionar para todos, pero funciona muy bien para mí y no tengo que preocuparme por agregar código a cada uno de mis controladores de vista. Pude mantener todo centralizado en la subclase UINavigationController.
Espero que esto ayude a alguien como a mí. Gracias, Jeremy.
Me gustaría dar una respuesta parcial a mi propia pregunta. Encontré la siguiente línea de código, utilizada en el método viewWillAppear
de mi tercer UIViewController
, para funcionar:
[[UIDevice currentDevice]
performSelector:NSSelectorFromString(@"setOrientation:")
withObject:(id)UIInterfaceOrientationPortrait];
Pero realmente no me gusta esta solución. Está utilizando un truco para asignar a una propiedad de solo lectura que de acuerdo con la documentación de Apple representa la orientación física del dispositivo. Es como decirle al iPhone que salte a la orientación correcta en la mano del usuario.
Estoy muy tentado de dejar esto en mi aplicación, ya que simplemente funciona. Pero no se siente bien así que me gustaría dejar la pregunta abierta para una solución limpia.
Me he enfrentado al mismo tipo de problema. Y resolvió mi problema como a continuación.
Si está utilizando el UINavigationController
para empujar los controladores de vista, entonces tiene que establecer los métodos a continuación.
extension UINavigationController{
override open var shouldAutorotate: Bool {
if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
{
return true
}
return false
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
{
return .portrait
}
return .landscapeRight
}
override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
{
return .portrait
}
return .landscapeRight
}
}
En lugar de LoginViewController
usa UIViewController
que quieras mostrar. En mi caso, quiero mostrar el LoginViewController
en el modo Portrait
Otros ViewControllers
en modo landscape
.
No tengo suficiente reputación para comentar la respuesta de @ Brian, así que agregaré mi nota aquí.
Brian mencionó que iOS6 le da el control de rotación al controlador raízViewController, esto no solo podría ser un UINavigationController como se mencionó sino también un UITabBarController, que fue para mí. Mi estructura se ve así:
- UITabBarController
- UINavigationController
- UIViewControllers ...
- UINavigationController
- UIViewControllers ...
- UINavigationController
Así que agregué los métodos primero en un UITabBarController personalizado, luego en un UINavigationController personalizado y finalmente en el UIViewController específico.
Ejemplo del UITabBarController y UINavigationController:
- (BOOL)shouldAutorotate {
return [self.viewControllers.lastObject shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.viewControllers.lastObject supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return [self.viewControllers.lastObject shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation];
}
No tengo suficiente reputación para responder la pregunta de @Ram S en la respuesta de @micmdk, así que agregaré mi nota aquí.
Cuando use UITabbarController , intente cambiar self.viewControllers.lastObject en el código de @ micmdk a self.selectedViewController de la siguiente manera:
- (BOOL)shouldAutorotate {
return [self.selectedViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.selectedViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
Puede implementar y reemplazar shouldAutorotate () y supportedInterfaceOrientations var en todas sus clases de View Controller que deberían presentarse en orientaciones diferentes a las definidas en PLIST de su aplicación.
Sin embargo, en una interfaz de usuario no trivial, es posible que enfrente un problema para agregarlo a docenas de clases y no desea convertirlas en todas las subclases de varias comunes que lo admiten (MyBaseTableViewController, MyBaseNavigationController y MyBaseTabBarController).
Como no puede anular directamente el método / var en UIViewController, puede hacerlo en sus subclases, que normalmente son clases base como la suya UITableViewController, UINavigationController y UITabBarController.
Por lo tanto, puede implementar algunas extensiones y aún configurar MyPreciousViewController para mostrar en orientaciones diferentes a todas las demás como este fragmento de código Swift 4:
extension UITableViewController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let last = self.navigationController?.childViewControllers.last,
last != self {
return last.supportedInterfaceOrientations
} else {
return [.portrait]
}
}
}
extension MyPreciousViewController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.portrait,.landscape]
}
}
extension UINavigationController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.portrait]
}
}
extension UITabBarController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.portrait]
}
}
Quería tener todos mis VCs bloqueados para orientación vertical, excepto uno. Esto es lo que funcionó para mí.
- Agregue soporte para todas las orientaciones en el archivo plist.
En el controlador de vista raíz, detecte el tipo de controlador de vista que está en la parte superior de la ventana y configure la orientación de la aplicación según corresponda en el método supportedInterfaceOrientations . Por ejemplo, necesitaba que mi aplicación gire solo cuando la vista web estaba en la parte superior de la pila. Esto es lo que agregué en mi rootVC:
-(NSUInteger)supportedInterfaceOrientations { UIViewController *topMostViewController = [[Utils getAppDelegate] appNavigationController].topViewController; if ([topMostViewController isKindOfClass:[SVWebViewController class]]) { return UIInterfaceOrientationMaskAllButUpsideDown; } return UIInterfaceOrientationMaskPortrait; }
Siendo que este es un hilo muy visto. Pensé que agregaría lo que creo que es la respuesta más fácil. Esto funciona para ios8 y hasta
-(BOOL)shouldAutorotate
{
return YES;
}
y
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
Eso es. ¡Disfrutar!
Ah, y mis ViewControllers están incrustados en un controlador de navegación, que no necesitaba crear subclase o configurar de ninguna manera.
Tuve el mismo problema y encontré una solución que me funciona. Para hacerlo funcionar, no es suficiente implementar - (NSUInteger)supportedInterfaceOrientations
en su UINavigationController. También necesita implementar este método en su controlador n. ° 3, que es el primero en ser solo retrato después de mostrar el controlador n. ° 4. Entonces, tengo el siguiente código en mi UINavigationController:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if (self.isLandscapeOK) {
// for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
En el controlador de vista # 3, agregue lo siguiente:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
No necesita agregar nada a sus controladores de vista n. ° 1, n. ° 2 y n. ° 4. Esto funciona para mí, espero que te ayude.
Utiliza el siguiente método para resolver este problema
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
devuelve solo la orientación que deseas !!!
Vaya a su archivo Info.plist y realice el cambio