iPhone: en mode paysage uniquement, après la première opération addSubview, UITableViewController ne tourne pas correctement

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

  •  06-07-2019
  •  | 
  •  

Question

Un projet Xcode illustratif minimal est disponible sur github .

Dans ma UIWindow, lorsque j'ajoute des seconde (et des suivantes) UITableView en tant que sous-vues, elles ne tournent pas correctement et apparaissent donc latéralement. Ceci est uniquement testé dans le simulateur. Voici un petit code pour vous:

- (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 apparaît de côté. Mettez en commentaire addSubview pour viewB et viewA apparaît correctement. Faites cela uniquement pour viewA, et viewB apparaît correctement.

Je ne crée pas ces UITableViewControllers via des NIB, bien que UIWindow le soit.

Au cas où vous vous le demanderiez, ShellTVC est un UITableViewController et implémente cette méthode:

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

De plus, j'ai défini UIInterfaceOrientation dans le fichier plist sur UIInterfaceOrientationLandscapeLeft.

Probablement liées - et sans réponse - aux questions SO, ici et ici .

Était-ce utile?

La solution

Je pense avoir trouvé un moyen, peut-être le bon, de le faire.

  1. Créer un " maître " La sous-classe UIViewController, qui implémente shouldAutorotate ..., et ajoute ceci comme seule vue de votre fenêtre.
  2. Pour alterner entre viewA et viewB, utilisez la combinaison de rejetModalViewControllerAnimated: & amp; presentModalViewController: animé: sur ce contrôleur de vue principale.

Voici du code:

// 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];
}

Pourquoi ça marche?

  1. Tous les changements d'orientation se font par les contrôleurs de vue, et non par les vues.

  2. Autant que je sache, la première vue ou sous-vue que vous ajoutez à votre fenêtre reçoit une sauce spéciale. Si cette vue possède un contrôleur de vue, la fenêtre le résout.

C’est-à-dire que, pour la première sous-vue, vous pouvez penser à ce code:

[window addSubview:masterVC.view];

comme faisant quelque chose comme ça (pas une vraie méthode!):

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

Je n'y comprends pas plus que ça. Je trouve que je peux le faire avec la première sous-vue, mais pas avec les autres, extrêmement perplexe. Plus d'informations sont les bienvenues et faites-moi savoir si cela vous a aidé ou non.

Autres conseils

Apparemment, si vous ajoutez une vue en tant qu'enfant de celle-ci, la rotation sera effectuée correctement. Ce n'est pas une bonne solution pour mon projet, mais il semble que ce soit la seule solution de contournement.

Malheureusement, vos sous-vues ne sont interrogées que sur les orientations prises en charge lors d'un changement d'orientation.

Je finis donc par définir l'orientation avant de placer le nouveau contrôleur de vue sur la pile si je sais qu'il a changé:

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 

Oui, il s'agit d'un appel non pris en charge.

Vous pouvez utiliser l'objet UIApplication pour forcer une orientation de périphérique particulière.

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

Oui, je pense que vous devez résoudre ce problème en utilisant plusieurs XIB. Je me souviens avoir vu cette solution dans l'un des livres que j'ai lus dans le passé. Sinon, vous devez jouer avec la traduction et la position de l'objet dans la vue ... il vaut mieux avoir XIB séparé.

Cela devrait fonctionner.

- (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);
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top