Comment contraindre l'autorotation à une seule orientation pour certaines vues, tout en permettant toutes les orientations sur d'autres?

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

Question

Cette question concerne la rotation des périphériques iOS et les vues contrôlées multiples dans un UinavigationController. Certaines vues devraient être contraint au portrait orientation, et certains devraient s'autorotate librement. Si vous essayez de créer la configuration la plus simple avec trois vues, vous remarquerez que le comportement d'autorotation a quelques bizarreries très désagréables. Le scénario est cependant très simple, donc je pense que je ne fais pas correctement l'implémentation d'autorotation, ou j'oublie quelque chose.

J'ai une application de démonstration très basique qui montre l'étrangeté, et j'ai fait une vidéo le montrant en action.

La configuration est très basique: trois contrôleurs de vue appelés FirstViewController, SecondViewController et ThirdViewController tous étendent un AbstractViewController qui montre une étiquette avec le nom de la classe et qui revient oui pour shouldAutorotateToInterfaceOrientation: Lorsque l'appareil est dans l'orientation du portrait. Le SecondViewController remplace la méthode pour permettre toutes les rotations. Les trois classes de béton ajoutent quelques carrés colorés pour pouvoir naviguer entre les vues en poussant et en faisant monter les contrôleurs sur / désactiver le UINavigationController. Jusqu'à présent, un scénario très simple, je dirais.

Si vous tenez l'appareil dans l'orientation du portrait ou du paysage, c'est le résultat que je voudrais non seulement réaliser, mais je m'attendrais également. Dans la première image, vous voyez que toutes les vues sont `` verticales '', et dans la seconde, vous voyez que seul le contrôleur de la deuxième vue contre-rotate l'orientation de l'appareil. Pour être clair, il devrait être possible de naviguer de la deuxième vue en mode paysage au troisième, mais parce que ce troisième ne prend en charge que l'orientation du portrait, il ne devrait être montré que dans l'orientation du portrait. La façon la plus simple de voir si les résultats sont corrects, c'est de regarder la position de la barre des transporteurs.

Expected view orientation for the device in portrait mode Expected view orientation for the device in landscape mode

Mais cette question est là parce que le résultat réel est complètement différent. Selon la vue dans laquelle vous êtes lorsque vous faites pivoter l'appareil et en fonction de la vue que vous naviguez ensuite, les vues ne tourneront pas (pour être spécifique, le didOrientFromInterfaceOrientation: la méthode n'est jamais appelée). Si vous êtes dans le paysage le second et que vous naviguez vers le troisième, il aura la même orientation que la seconde (= mauvais). Si vous naviguez du deuxième retour au premier, l'écran tournera en un mode portrait «forcé», et la barre de transporteur sera au sommet physique de l'appareil, quelle que soit la façon dont vous le tenez. La vidéo le montre plus en détail.

Actual view orientation for the device in landscape mode

Ma question est double:

  1. Pourquoi le premier contrôleur de vue tourne-t-il en arrière, mais pas le troisième?
  2. Qu'est-ce qui doit être fait pour obtenir le bon comportement de vos vues lorsque vous voulez que certaines vues s'autorotent, mais pas d'autres?

Cheers, EP.

Edit: En dernier recours avant de mettre une prime dessus, j'ai complètement réécrit cette question pour être plus courte, plus claire et, espérons-le, plus invitante à donner une réponse.

Était-ce utile?

La solution

La réponse courte est que vous utilisez UinavigationController, et cela ne fonctionnera pas comme vous le souhaitez. Des documents d'Apple:

Pourquoi mon UIViewController ne tourne-t-il pas avec l'appareil?

Tous les contrôleurs de vue d'enfants dans votre UitabbarController ou UinavigationController ne sont pas d'accord sur un ensemble d'orientation commun.

Pour vous assurer que tous vos contrôleurs de vue d'enfants tournent correctement, vous devez implémenter de l'autoTorotateToInterfaceOrientation pour chaque contrôleur de vue représentant chaque onglet ou niveau de navigation. Chacun doit convenir de la même orientation pour que ce rotation se produise. Autrement dit, ils devraient tous revenir oui pour les mêmes positions d'orientation.

Vous pouvez en savoir plus sur Voir les problèmes de rotation ici.

Vous devrez faire en sorte que votre propre vue / gestion de la pile de contrôleur ce que vous voulez faire.

Autres conseils

Faire un délégué boléen dans l'application pour contrôler l'orientation que vous souhaitez, par exemple, faire un bool pour activer le portrait et dans votre contrôleur de vue, vous souhaitez autoriser le portrait à lui activer par une application partagée

Dans votre contrôleur de vue, où vous souhaitez activer ou désactiver l'orientation que vous souhaitez.

((APPNAMEAppDelegate *)[[UIApplication sharedApplication] delegate]).enablePortrait= NO;

Dans l'application déléguée.

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    NSLog(@"Interface orientations");
    if(!enablePortrait)
        return UIInterfaceOrientationMaskLandscape;
    return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait;
}

Ces méthodes seront tirées chaque fois que vous faites pivoter l'appareil, en fonction de ces bools permettent l'orientation que vous souhaitez.

Il y a une question similaire il y a quelques années avec un certain nombre de réponses. Voici une réponse récente de quelqu'un à cette question:
Existe-t-il un moyen documenté de définir l'orientation de l'iPhone?

D'après ce que je comprends, c'est un problème que beaucoup de gens ont et la plupart des pirates sont le seul moyen de le résoudre. Regardez ce fil si vous ne l'avez pas vu auparavant et voyez si quelque chose fonctionne pour vous.

Sur une note latérale, j'ai eu un problème similaire il y a quelque temps quand j'appelais quelque chose en Shoundautorotate et j'ai ajouté du code à viewWillAppear pour essayer de le réparer. Honnêtement, je ne me souviens pas si cela a fonctionné et que je n'ai plus de Mac pour l'essayer, mais j'ai trouvé le code et je vais le coller ici au cas où cela vous inspirera.

- (void)viewWillAppear:(BOOL)animated{
  UIInterfaceOrientation o;
  switch ([UIDevice currentDevice].orientation) {
    case UIDeviceOrientationPortrait:
        o = UIInterfaceOrientationPortrait;
        break;
    case UIDeviceOrientationLandscapeLeft:
        o = UIInterfaceOrientationLandscapeLeft;
        break;
    case UIDeviceOrientationLandscapeRight:
        o = UIInterfaceOrientationLandscapeRight;
        break;
    default:
        break;
  }

  [self shouldAutorotateToInterfaceOrientation:o];
}

N'utilisez pas ce hack, Apple rejetera l'application en fonction de l'utilisation de «API privée»

Par souci de référence, je laisserai ma réponse ici, mais l'utilisation de l'API privée ne passera pas au-delà du comité d'examen. J'ai appris quelque chose aujourd'hui: D comme @Younce a cité correctement les documents Apple, ce que je veux ne peut pas être réalisé avec le UinavigationContrller.

J'avais deux options. Tout d'abord, j'aurais pu écrire mon propre substitut de contrôleur de navigation, avec toutes les horreurs que l'on aurait rencontrées en le faisant. Deuxièmement, j'aurais pu pirater la rotation dans les contrôleurs de vue, en utilisant une caractéristique sans papiers d'Uidevice appelée setOrientation:animated:

Parce que la seconde était tentante, je suis allé pour celui-là. C'est ce que j'ai fait. Vous aurez besoin d'une catégorie pour supprimer les avertissements du compilateur sur le secteur qui n'existe pas:

@interface UIDevice (UndocumentedFeatures) 
-(void)setOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
-(void)setOrientation:(UIInterfaceOrientation)orientation;
@end

Ensuite, vous devez vérifier les orientations prises en charge sur viewWillAppear:. À côté des méthodes Uidevice utilisées ici, vous pouvez également forcer l'orientation du portrait en présentant un contrôleur de vue modale, mais cela se produira instantanément et non animé, c'est donc ma manière préférée:

-(void)viewWillAppear:(BOOL)animated {
    UIDevice *device = [UIDevice currentDevice];
    UIDeviceOrientation realOrientation = device.orientation;

    if ([self shouldAutorotateToInterfaceOrientation:realOrientation]) {
        if (realOrientation != [UIApplication sharedApplication].statusBarOrientation) {

            // Resetting the orientation will trigger the application to rotate
            if ([device respondsToSelector:@selector(setOrientation:animated:)]) {
                [device setOrientation:realOrientation animated:animated];
            } else {
                // Yes if Apple changes the implementation of this undocumented setter,
                // we're back to square one.
            }
        }
    } else if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
        if ([device respondsToSelector:@selector(setOrientation:animated:)]) {

            // Then set the desired orientation
            [device setOrientation:UIDeviceOrientationPortrait animated:animated];

            // And set the real orientation back, we don't want to truly mess with the iPhone's balance system.
            // Because the view does not rotate on this orientation, it won't influence the app visually.
            [device setOrientation:realOrientation animated:animated];
        }
    }
}

L'astuce consiste à toujours garder l'orientation interne de l'appareil à l'orientation «réelle» de l'appareil. Si vous commencez à changer cela, la rotation de votre application sera déséquilibrée.

Mais comme je le sais maintenant, c'est juste un moyen sûr de rejeter votre application. Donc, l'option numéro deux n'est qu'une mauvaise option. Réécrivez cette navigation Controller, ou faites en sorte que toutes vos vues prennent en charge le même ensemble d'orientation.

Cheers, EP.

Dans iOS 6, cela est devenu un problème très simple. Créez simplement une classe spéciale pour les vues que vous souhaitez vous autoroter. Ensuite, dans votre rootvc, ajoutez ceci.

-(BOOL)shouldAutorotate{
       BOOL should = NO;

       NSLog(@"%@", [self.viewControllers[self.viewControllers.count-1] class]);
       if ([self.viewControllers[self.viewControllers.count-1] isKindOfClass:[YourAutorotatingClass class]]) {
             should = YES;
       }


       return should;
}

Je sais que c'est une vieille question, mais je pensais que cela valait la peine de mentionner.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top