Pregunta

Tengo una jerarquía de vista anidada para una aplicación para iPad que admite cambios de orientación. Se ve similar a lo siguiente.

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

Me gustaría bloquear la orientación para algunas de mis subvistas, mientras que permiten que otros se rompan y redimensen automáticamente. Parece que no puedo descubrir cómo lograr esto.

Un enfoque parece estar rotar las subvisiones manualmente dentro de willAnimateRotationToInterfaceOrientation:. Eso no es particularmente atractivo dado que el SDK está ejecutando una rotación que solo estaría deshaciendo.

¿Hay alguna forma de simplemente deshabilitar los cambios de orientación para las subvistas o algún otro método para reestructurar mi jerarquía?

¿Fue útil?

Solución

La autorotación es manejada por UIViewController de una vista (shouldAutorotateToInterfaceOrientation:), entonces un enfoque es organizar su jerarquía de modo que las vistas rotatables sean administradas por un controlador de visión y vistas no rotatorias por otro controlador de visión. Ambas vistas raíz de UiviewController necesitan agregar a la ventana/supervisión.

La sutileza aquí es que si tiene dos vistas del controlador de vista en el mismo nivel (es decir, agregado a través de addSubview:), solo el primer controlador de vista (generalmente la ventana rootViewController) recibirá el shouldAutorotateToInterfaceOrientation: mensaje.

Utilicé este enfoque yo mismo para lograr una barra de herramientas que gira, mientras que la vista principal no.

QA1688 de preguntas y respuestas técnicas de Apple ("¿Por qué mi UIViewController no gira con el dispositivo?") habla un poco sobre este problema.


Actualización de iOS 6:

La autorotación ahora usa UIViewController's shouldAutorotate y supportedInterfaceOrientations métodos. shouldAutorotate devoluciones YES Por defecto, pero recuerde que un controlador de vista que no sea el rootViewController cuya vista es una subvisión directa de la ventana no recibirá devoluciones de llamada de rotación de todos modos.


Código de muestra para iOS 6:

Cree un nuevo proyecto utilizando la plantilla de "Aplicación de vista única" y asegúrese de que se verifique "Usar guiones gráficos". Usaremos el proporcionado ViewController clase como controlador de vista giratoria (¡cámbiele el nombre si lo desea!), Y cree un segundo UIViewController subclase llamado NonRotatingViewController. Aunque este controlador de vista nunca recibirá las devoluciones de llamada de rotación, para la integridad y la claridad, agregue el siguiente código en NonRotatingViewController.m:

- (BOOL)shouldAutorotate
{
    return NO;
}

En el MainStoryboard archivo, arrastre un nuevo objeto de controlador de vista y configure su clase en NonRotatingViewController, y establece su identificación del guión gráfico en "no RotatingVC". Mientras esté allí, cambie el color de fondo del controlador de vista giratoria para borrar (la vista no giratoria se agregará debajo de este) y agregue una etiqueta a cada vista. En AppDelegate.m, agregue el siguiente código:

#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 solo instancia un controlador de vista no giratorio y agregue su vista directamente a la ventana (NB en este punto la ventana de la ventana rootViewController ya ha sido establecido por el guión gráfico).

Ejecutar el proyecto. ¡Gire el dispositivo y maravillado al ver una etiqueta girando mientras la otra se queda quieta!


Código de muestra pre iOS 6:

Hice esto en un nuevo proyecto: una nueva aplicación basada en Vistas funcionará bien. Agregue dos nuevos controladores de vista: RotatingViewController y NonRotatingViewController. Dentro de cada una de sus puntas, acabo de agregar una etiqueta para describir si la vista debe girar o no. Agregue el siguiente código:

'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.

Otros consejos

Aquí hay otra forma. Simplemente coloque este código en su 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.

Mi enfoque de resolver este problema es hacer una contramedida utilizando UINotification Para detectar la rotación automática y girar la vista al revés.

Encuentra 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);
    }];
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top