iPhone: solo en modo horizontal, después de agregar addSubview por primera vez, UITableViewController no gira correctamente

StackOverflow https://stackoverflow.com/questions/1632117

  •  06-07-2019
  •  | 
  •  

Pregunta

Un proyecto Xcode ilustrativo mínimo para esto está disponible en github .

En mi UIWindow, cuando agrego los segundos (y posteriores) UITableView como subvistas, no giran correctamente y, por lo tanto, aparecen de lado. Esto solo se prueba en el simulador. Aquí hay un pequeño código para usted:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    ShellTVC* viewA = [[ShellTVC alloc] initWithTitle:@"View A"];
    ShellTVC* viewB = [[ShellTVC alloc] initWithTitle:@"View B"];

    // The first subview added will rotate to landscape correctly. 
    // Any subsequent subview added will not.

    // You may try this by various commentings and rearranging of these two statements.

    [window addSubview:[viewA tableView]];
    [window addSubview:[viewB tableView]];

    [window makeKeyAndVisible];
}

viewB aparece de lado. Comente addSubview para viewB, y viewA aparece correctamente. Haga eso solo para viewA, y viewB aparece correctamente.

No estoy creando estos UITableViewControllers a través de NIB, aunque la UIWindow sí.

En caso de que se lo pregunte, ShellTVC es un UITableViewController e implementa este método:

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

Además, he configurado UIInterfaceOrientation en el archivo plist a UIInterfaceOrientationLandscapeLeft.

Probablemente relacionado - y sin respuesta - preguntas SO aquí y aquí .

¿Fue útil?

Solución

Creo que descubrí una forma, posiblemente la correcta, de hacer esto.

  1. Crear un "maestro" La subclase UIViewController, que implementa shouldAutorotate ..., y agrega esto como la única vista en su ventana.
  2. Para alternar entre viewA o viewB, use la combinación de despedirModalViewControllerAnimated: & amp; presentModalViewController: animado: en este controlador de vista maestro.

Aquí hay un código:

// this doesn't really do much but implement shouldAutorotate...
@interface MasterViewController : UIViewController
@end

@implementation MasterViewController
- (BOOL) shouldAutorotateToInterfaceOrientation(UIInterfaceOrientation)interfaceOrientation {
     return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
@end

@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
    MasterViewController* masterVC;
    UIViewController* activeTVC;
    UIViewController* onDeckTVC;
}
@end

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    UIViewController* masterVC = [[MasterViewController alloc] init];        
    activeTVC = [[ShellTVC alloc] initWithTitle:@"View A"];
    onDeckTVC = [[ShellTVC alloc] initWithTitle:@"View B"];
    [window addSubview:masterView.view];
    [window makeKeyAndVisible];
    [masterVC presentModalViewController:activeTVC animated:NO];
}

// you would call this to toggle between "View A" and "View B"
- (void)toggleTVC {
    UITableViewController *hold = activeTVC;
    activeTVC = onDeckTVC;
    onDeckTVC = hold;
    [masterVC dismissModalViewControllerAnimated:NO];   
    [masterVC presentModalViewController:activeTVC animated:NO];
}

¿Por qué funciona esto?

  1. Todos los cambios de orientación fluyen a través de los controladores de vista, no de las vistas.

  2. Por lo que puedo decir, la primera vista o subvista que agrega a su ventana obtiene un poco de salsa especial. Si esa vista tiene un controlador de vista, la ventana se da cuenta.

Es decir, solo para la primera subvista, puede pensar en este código:

[window addSubview:masterVC.view];

como hacer algo como esto (¡no es un método real!):

[window addSubview:masterVC.view withViewController:masterVC];

No entiendo nada más sobre eso que eso. Encuentro el hecho de que puedo hacer esto con la primera subvista, pero no con otras, sumamente desconcertante. Más información bienvenida, y por favor avíseme si esto le ayudó o no.

Otros consejos

Aparentemente, si agrega la vista como hijo de viewS, se rotará correctamente. Esta no es una gran solución para mi proyecto, pero parece que podría ser la única solución.

Lamentablemente, a sus subvistas solo se les pregunta qué orientaciones admiten cuando se produce un cambio de orientación.

Así que termino configurando la orientación antes de insertar el nuevo controlador de vista en la pila si sé que ha cambiado:

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 

Sí, esta es una llamada no admitida.

Puede usar el objeto UIApplication para forzar una orientación particular del dispositivo.

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];

Sí, creo que debe resolver este problema teniendo múltiples XIB. Recuerdo haber visto esta solución a través de uno de los libros que leí en el pasado. Si no, tienes que jugar con la traducción y la posición del objeto en la vista ... mejor tener XIB separado.

Esto debería funcionar.

- (void)viewDidLoad {
    if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) || 
        ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) 

    {
        self.view.frame = CGRectMake(0, 0, 1024, 748);

    } else {
        self.view.frame = CGRectMake(0, 0, 768, 1004);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top