Tengo una vista anidada jerarquía para una aplicación de iPad que soporta los cambios de orientación. Parece similar a la siguiente.

UIViewController
    UIView
        - UIView
            - UIImageView (disable rotation)
            - UIImageView
            - UIView (disable rotation)
        - UIView
        - UIView
        ...

Me gustaría bloquear la orientación de algunos de mis subvistas, permitiendo a otros auto-rotar y cambiar el tamaño. Yo no puedo parecer para averiguar cómo lograr esto.

Un enfoque parece ser la rotación de la subvistas manualmente dentro de willAnimateRotationToInterfaceOrientation:. Que no es particularmente atractivo, dado el SDK es la ejecución de una rotación que acabo de ser perdición.

Hay una manera de simplemente deshabilitar los cambios de orientación de subvistas o algún otro método para reestructurar la jerarquía?

InformationsquelleAutor Jason George | 2011-09-08

3 Comentarios

  1. 22

    La autorrotación es manejado por una vista UIViewController (shouldAutorotateToInterfaceOrientation:), por lo que un enfoque es el de organizar su jerarquía tal que giratorio vistas son administrados por un controlador de vista, y no se puede girar de las vistas al otro controlador de vista. Ambos de estos UIViewController raíz de puntos de vista, a continuación, añada a la ventana/superview.

    La sutileza aquí es que si usted tiene dos vistas del controlador de puntos de vista sobre el mismo nivel (es decir, añadido a través de addSubview:), sólo la primera vista controlador (normalmente, la ventana del rootViewController) recibirá el shouldAutorotateToInterfaceOrientation: mensaje.

    He utilizado este enfoque a mí mismo para lograr una barra de herramientas que gira, mientras que la vista principal no.

    Técnico de Apple Q&UN QA1688 («¿por Qué no mi UIViewController girar con el dispositivo?») habla un poco acerca de este tema.

    Actualización para iOS 6:

    Autorotación ahora utiliza UIViewController‘s shouldAutorotate y supportedInterfaceOrientations métodos. shouldAutorotate devuelve YES por defecto, pero recuerde que un controlador de vista distinto de la rootViewController cuyo punto de vista es un directo subvista de la ventana NO va a recibir la rotación de las devoluciones de llamada de todos modos.


    Código de ejemplo para iOS 6:

    Crear un nuevo proyecto utilizando la «Vista Única de la Aplicación de la plantilla», y asegurar el Uso de Storyboards» está marcada. Vamos a utilizar el ViewController de la clase como de la rotación de la vista controlador (cambiarle el nombre si te gusta!), y crear un segundo UIViewController subclase llamada NonRotatingViewController. Aunque este punto de vista controlador nunca incluso de recibir la rotación de las devoluciones de llamada, la integridad y la claridad agregue el código siguiente en NonRotatingViewController.m:

    - (BOOL)shouldAutorotate
    {
        return NO;
    }

    En el MainStoryboard archivo, arrastre un nuevo controlador de vista del objeto y establece su clase para NonRotatingViewController, y establecer su Guión ID a «NonRotatingVC». Mientras estás allí, cambiar la rotación del controlador de vista de ver el color de fondo claro (la no rotación de la vista será añadido por debajo de este), y agregar una etiqueta a cada vista. En AppDelegate.m, agregue el código siguiente:

    #import "NonRotatingViewController.h"
    
    //...
    //...
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        //Override point for customization after application launch.
        UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
        NonRotatingViewController *nonRotatingVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"NonRotatingVC"];
        [self.window addSubview:nonRotatingVC.view];
        return YES;
    }

    Esto es sólo crear una instancia de un no rotación de la vista controlador y la adición de su vista directamente a la ventana (N. B. en este punto de la ventana rootViewController ya ha sido establecido por el guión).

    Ejecutar el proyecto. Gire el dispositivo y maravillarse con la vista de una etiqueta de rotación, mientras que el otro permanece todavía!


    Ejemplo de Código pre iOS 6:

    Hice esto en un nuevo proyecto, un nuevo punto de Vista basado en la Aplicación estará bien. Agregar dos nuevos visualización de controladores: RotatingViewController y NonRotatingViewController. Dentro de cada una de sus puntas acabo de añadir una etiqueta para describir si la vista debe girar o no. Agregue el código siguiente:

    RotatingViewController.m

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        return YES;
    }


    NonRotatingViewController.m

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        if (interfaceOrientation == UIInterfaceOrientationPortrait) {    //Or whatever orientation it will be presented in.
            return YES;
        }
        return NO;
    }


    AppDelegate.m

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        RotatingViewController *rotating = [[RotatingViewController alloc] initWithNibName:@"RotatingViewController" bundle:nil];
        self.rotatingViewController = rotating;
        [rotating release];
    
        NonRotatingViewController *nonRotating = [[NonRotatingViewController alloc] initWithNibName:@"NonRotatingViewController" bundle:nil];
        self.nonRotatingViewController = nonRotating;
        [nonRotating release];
    
        [self.window addSubview:self.rotatingViewController.view];
        [self.window insertSubview:self.nonRotatingViewController.view belowSubview:self.rotatingViewController.view];
    
        [self.window makeKeyAndVisible];
    
        return YES;
    }

    Espero que esto ayude.

    • Este enfoque no parece estar funcionando para mí. He configurado una jerarquía con un padre controlador de vista que contiene dos niños de la vista de los controladores (portraitViewController y rotateViewController), cada uno con un UIImageView con shouldAutorotateToInterfaceOrientation de regreso NO para el retrato y SÍ para girar. Si me puse shouldAutorotateToInterfaceOrientation a NO en la casa de mis padres, la orientación es estático, como se esperaba. Configuración de shouldAutorotateToInterfaceOrientation para SÍ, en mi padre, sin embargo, hace girar. Cualquier posibilidad de que usted podría publicar algo de código? He pasado mal en algún lugar.
    • He añadido el código de ejemplo como se solicitó.
    • Vista de los Controladores pueden ser bastante temperamental y particular – con un custom ‘contenedor’ de la controladora como la ha descrito podría ser lo que está causando el problema. Me gustaría asegurarse de que su hijo controlador de vista de las vistas de ambos están conectados directamente a la ventana de la aplicación.
    • Gracias StuDev. +1 en todo. El ‘contenedor’ controlador es sin duda la causa del problema.
    • Funciona como un encanto! +1
    • gracias, esto es complicado cosas y esta solución funcionó a la perfección para mí. también me gustaría añadir que la separación de los puntos de vista significa mi giratoria de vista necesita pasar a través de eventos de toque… esta respuesta ayudaron con esto: stackoverflow.com/questions/7381155/…
    • En iOS 6, es probable que necesite para establecer la raíz de controlador de vista. Esto funcionó para mí: self.window.rootViewController = self.rotatingViewController;, a Continuación, llamar [self.window insertSubview: self.nonRotatingViewController.view belowSubview:self.rotatingViewController.view]; (En mi caso – la suya puede ser diferente.)
    • +1 , agradable y sin tocar el concepto..
    • Esto no parece correcto. ¿Dónde se establece el auto.de la ventana.rootViewController? Tiene dos viewControllers, pero no se establece como su aplicación rootViewController.
    • Un punto interesante – supongo que Apple plantillas de proyecto han cambiado, y que la raíz de controlador de vista se fijó en el interface builder (yo no tengo una manera de comprobar esto, sin embargo). La vista controlador que necesita para recibir la rotación de las devoluciones de llamada en efecto, es necesario establecer que la ventana del rootViewController. Voy a actualizar la respuesta a proporcionar un up-to-fecha de trabajo de ejemplo.
    • Supongo que estoy teniendo un tiempo difícil la comprensión de cómo funciona esto. En primer lugar, la inserción de nonRotatingViewController la vista en la ventana de la vista de jerarquía, en realidad no activar el nonRotatingViewController, y sólo con los lugares que ver en el control de la ventana, que no hace las cosas como autorotación. En efecto, se podría haber utilizado cualquier punto de vista que has creado y que la carga de la misma manera y el nonRotatingViewController es un no-op. Me puede decir donde me equivoco?
    • No estoy seguro de lo que quieres decir por «activar» el controlador de vista. Una vista controlador gestiona una jerarquía de puntos de vista, y esto es cierto de la nonRotatingViewController — todavía gestiona la carga & presentación de su punto de vista (viewDidLoad, viewWillAppear etc) y otras controlador de tareas tales como la presentación adicional de vista de los controladores. Mediante la adición de su vista directamente a la ventana, todo lo que estamos haciendo es prevenir nonRotatingViewController a partir de la recepción de los métodos de la rotación. En la rotación, la ventana sólo se ajusta el marco de & rotación de la rootViewController.
    • Mientras que sería posible lograr algo similar por la adición de cualquier UIView instancia como una subvista de la ventana, usted no debe hacerlo, ya que cada punto de vista debe ser administrado por un UIViewController (como el controlador de vista de la raíz de vista, o como parte de una jerarquía cuya raíz punto de vista es gestionado por un controlador de vista). Tal vez donde se confundan es el asumir que la UIWindow hace el trabajo de un controlador de vista – UIWindow es una subclase de UIView, por lo tanto usted puede agregar vistas subordinadas a ella. NonRotatingViewController‘s vista sigue siendo administrado por el NonRotatingViewController.
    • alguna idea de cómo conseguir esta trabajando en iOS 8?
    • Creo que en iOS 8 que realmente girar la ventana, por lo que, para ser estable en la rotación del mundo, su punto de vista debe girar en la dirección opuesta. La pregunta es: «¿Está alguno realmente vista fija en ese nuevo mundo?»
    • Para su INFORMACIÓN, he resuelto el problema de la creación de 2 de windows: uno de rotación y la segunda fija. Cada ventana tiene su propia raíz de controlador de vista de uno fijo, otro de rotación 🙂

  2. 10

    Aquí es de otra manera. Sólo tiene que colocar este código en tu viewController viewDidLoad:

        YourAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
            //the view you don't want rotated (there could be a heierarchy of views here):
        UIView *nonRotatingView = [[UIView alloc] initWithFrame:CGRectMake(100,0,30,500)];
        nonRotatingView.backgroundColor = [UIColor purpleColor];
    
            //make sure self.view and its children are transparent so you can see through to this view that will not be rotated behind self.view.
    
        [delegate.window insertSubview:nonRotatingView  belowSubview:self.view];
    
            //you can't put it in the front using:
            //   [delegate.window insertSubview:nonRotatingView aboveSubview:self.view];
            //It will show up the same as before
    
        //you should declare nonRotatingView as a property so you can easily access it for removal, etc.
    • Este es el trabajo perfecto para mí! Más simple que la otra solución.
    • Alguien tiene que explicar por qué esto funciona debido a que el código no se haga evidente
    • El nonRotatingView se coloca entre la ventana de la aplicación y el ViewControllers vista y que no esté gestionada por el viewcontroller. El viewcontroller va a manejar los cambios de orientación de sus puntos de vista, y se ignoran este punto de vista que se colocó entre ella y la ventana.
    • He implementado esta como tengo un AVCaptureSession en mi punto de Vista Controlador que deseo no debe girar, pero quiero que la no rotación de la vista a todo lo ancho y altura de mi Vista Controlador auto.ver como estoy abriendo mi cámara, pero Cuando hago el full tamaño de los botones en mi auto.vista del Controlador de Vista no son visibles alguna idea de cómo puedo hacerlos visibles mientras se mantiene la no rotación de la vista de pantalla completa
  3. 4

    Mi enfoque de la solución de este problema es hacer una contramedida utilizando UINotification para detectar la rotación automática y rotación de la vista de otro modo.

    Encontrar el código completo aquí:

    https://gist.github.com/ffraenz/5945301

    - (void)orientationDidChangeNotificationReceived:(NSNotification *)notification
    {
        //find out needed compass rotation
        // (as a countermeasure to auto rotation)
        float rotation = 0.0;
    
        if (self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
            rotation = M_PI;
        else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
            rotation = M_PI / 2.0;
        else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)
            rotation = M_PI / (- 2.0);
    
        //rotate compass without auto rotation animation
        // iOS rotation animation duration is 0.3
        // this excludes the compassView from the auto rotation
        // (same effect as in the camera app where controls do rotate and camera viewport don't)
        [UIView animateWithDuration:0.3 animations:^(void) {
            self.compassView.transform = CGAffineTransformMakeRotation(rotation);
        }];
    }
    • Esto funciona bien para iOS7, pero por alguna razón, no funciona en iOS 8

Dejar respuesta

Please enter your comment!
Please enter your name here