web-dev-qa-db-fra.com

Comment forcer UIViewController à l'orientation Portrait dans iOS 6

Comme ShouldAutorotateToInterfaceOrientation est obsolète dans iOS 6 et que je l’utilisais pour forcer une vue particulière à portrait uniquement, quelle est la bonne façon de procéder dans iOS 6? Ce n'est que pour une zone de mon application, toutes les autres vues peuvent pivoter.

85
Neal

Si vous souhaitez que tous nos contrôleurs de navigation respectent le contrôleur de la vue de dessus, vous pouvez utiliser une catégorie pour ne pas avoir à modifier et modifier un grand nombre de noms de classes.

@implementation UINavigationController (Rotation_IOS6)

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

Comme le soulignent quelques commentaires, il s’agit d’une solution rapide au problème. Une meilleure solution est la sous-classe UINavigationController et placez ces méthodes ici. Une sous-classe aide également à supporter 6 et 7.

117
Anthony

L’équipe Ray Wenderlich décrit précisément la meilleure façon de procéder pour iOS6 dans "iOS6 By Tutorials" - http://www.raywenderlich.com/ et est préférable au sous-classement UINavigationController pour la plupart cas.

J'utilise iOS6 avec un storyboard qui inclut un UINavigationController défini comme contrôleur de vue initial.

//AppDelegate.m - cette méthode n'est pas disponible avant iOS6 malheureusement

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

if(self.window.rootViewController){
    UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
    orientations = [presentedViewController supportedInterfaceOrientations];
}

return orientations;
}

//MyViewController.m - renvoie toutes les orientations que vous souhaitez prendre en charge pour chaque UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}
63
Phil

Cette réponse se rapporte aux questions posées dans les commentaires du post du PO:

Pour forcer une vue à apparaître dans une orientation donnée, mettez ce qui suit dans viewWillAppear:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
    UIViewController *c = [[UIViewController alloc]init];
    [self presentModalViewController:c animated:NO];
    [self dismissModalViewControllerAnimated:NO];
}

C'est un peu un bidouillage, mais cela oblige le UIViewController à être présenté en portrait même si le contrôleur précédent était en mode paysage

PDATE pour iOS7

Les méthodes ci-dessus sont maintenant obsolètes. Par conséquent, pour iOS 7, utilisez les éléments suivants:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
     UIViewController *c = [[UIViewController alloc]init];
     [c.view setBackgroundColor:[UIColor redColor]];
     [self.navigationController presentViewController:c animated:NO completion:^{
            [self.navigationController dismissViewControllerAnimated:YES completion:^{
            }];
     }];
}

Fait intéressant, au moment de la rédaction, le cadeau ou le rejeter doit être animé. Si ni l'un ni l'autre, alors vous obtiendrez un écran blanc. Aucune idée pourquoi cela fait fonctionner, mais ça marche! L'effet visuel est différent selon l'animation.

39
Craig Watkinson

J'ai donc rencontré le même problème lors de l'affichage de vues modales en mode portrait. Normalement, je créerais un UINavigationController, définirais le viewController comme le rootViewController, puis afficherais le UINavigationController sous la forme d'une vue modale. Mais avec iOS 6, le viewController demandera maintenant à navigationController de définir les orientations de son interface prises en charge (qui, par défaut, concerne désormais tout l’iPad et tout sauf la tête en bas pour l’iPhone).

Solution: Je devais sous-classer UINavigationController et substituer les méthodes d'autorotation. Genre de boiteux.

- (BOOL)shouldAutorotate {
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
// pre-iOS 6 support 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
36
rocky

IOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

IOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2

    //    return UIInterfaceOrientationMaskPortrait; 
    //    or
          return 2;
}
15
Roshan Jalgaonkar

Je ne suis pas d'accord avec la réponse @aprato, car les méthodes de rotation UIViewController sont déclarées dans les catégories elles-mêmes, ce qui entraîne un comportement indéfini si vous remplacez alors dans une autre catégorie. Il est plus sûr de les remplacer dans une sous-classe UINavigationController (ou UITabBarController).

En outre, cela ne couvre pas le scénario dans lequel vous enfoncez/présentez/passez d'une vue Paysage dans un portrait uniquement VC ou vice-versa. Pour résoudre ce problème épineux (jamais abordé par Apple), vous devriez:

Dans iOS <= 4 et iOS> = 6:

UIViewController *vc = [[UIViewController alloc]init];
[self presentModalViewController:vc animated:NO];
[self dismissModalViewControllerAnimated:NO];
[vc release];

sous iOS 5:

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];

Celles-ci obligeront VRAIMENT UIKit à réévaluer toutes vos Autorisations de base, InterfaceOrientations prises en charge, etc.

10
Rafael Nobre

J'ai une très bonne approche de mélange (https://stackoverflow.com/a/13982508/2516436 et https://stackoverflow.com/a/17578272/2516436

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
    NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;


    if(self.window.rootViewController){
        UIViewController *presentedViewController = [self topViewControllerWithRootViewController:self.window.rootViewController];
        orientations = [presentedViewController supportedInterfaceOrientations];
    }

    return orientations;
}

- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}

et renvoyez toutes les orientations que vous souhaitez prendre en charge pour chaque UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}
3
Alex Guerra

Ne soyez pas ennuyeux ici, mais auriez-vous la gentillesse de partager votre sous-classe? Je vous remercie.

edit: eh bien, je l’ai finalement fait, la sous-classe était simple à faire. Il me suffisait de déclarer navigationController dans AppDelegate comme UINavigationControllerSubclass à la place de la valeur par défaut UINavigationController, puis de modifier votre sous-classe avec:

- (BOOL)shouldAutorotate {
    return _shouldRotate;
}

afin que je puisse définir n'importe quelle vue que je veux faire pivoter ou non en appelant à viewDidLoad

_navController = (UINavigationController *)self.navigationController;
[_navController setShouldRotate : YES / NO]

J'espère que cette astuce aidera les autres aussi, merci pour votre conseil!

Astuce: utilisez

- (NSUInteger)supportedInterfaceOrientations

dans vos contrôleurs de vue, vous ne finirez donc pas par avoir une vue portrait souhaitée en mode paysage ou inversement.

1
Roland

J'ai une application universelle relativement complexe utilisant UISplitViewController et UISegmentedController, et quelques vues à présenter dans Paysage à l'aide de presentViewController. En utilisant les méthodes suggérées ci-dessus, j'ai réussi à faire fonctionner l'iPhone ios 5 et 6 de manière acceptable, mais pour une raison quelconque, l'iPad a tout simplement refusé de se présenter sous la forme Paysage. Enfin, j'ai trouvé une solution simple (mise en œuvre après des heures de lecture et d'essais et erreurs) qui fonctionne à la fois pour les appareils et pour iOS 5 et 6.

Étape 1) Sur le contrôleur, spécifiez l'orientation requise (plus ou moins comme indiqué ci-dessus)

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

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    NSInteger mask = UIInterfaceOrientationMaskLandscape;
    return mask;

}

Étape 2) Créez une sous-classe UINavigationController simple et implémentez les méthodes suivantes

-(BOOL)shouldAutorotate {
        return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
        return UIInterfaceOrientationMaskLandscape;
}

Étape 3) Présentez votre viewController

vc = [[MyViewController alloc]init];
MyLandscapeNavigationController *myNavigationController = [[MyLandscapeNavigationController alloc] initWithRootViewController:vc];
[self myNavigationController animated:YES completion:nil];

J'espère que cela est utile à quelqu'un.

1
user216661

Les réponses utilisant des sous-classes ou des catégories pour autoriser les VC dans les classes UINavigationController et UITabBarController fonctionnent bien. Le lancement d'un modal en mode portrait uniquement à partir d'un contrôleur de barre d'onglets en mode paysage a échoué. Si vous avez besoin de le faire, utilisez l’astuce consistant à afficher et masquer une vue modale non animée, mais faites-le dans la méthode viewDidAppear. Cela n'a pas fonctionné pour moi dans viewDidLoad ou viewWillAppear.

En dehors de cela, les solutions ci-dessus fonctionnent bien.

0
Peter

Pour Monotouch, vous pouvez le faire de cette façon:

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
    {
    return UIInterfaceOrientationMask.LandscapeRight;
}

public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
    {
    return UIInterfaceOrientation.LandscapeRight;
}
0
TJS

Je ne l'ai pas testé moi-même, mais la documentation indique que vous pouvez maintenant remplacer ces méthodes: supportedInterfaceOrientations et preferredInterfaceOrientationForPresentation.

Vous pouvez probablement obtenir ce que vous voulez en définissant uniquement l'orientation souhaitée dans ces méthodes.

0
J_D

Je vois beaucoup répondre mais je ne comprends pas l’idée particulière et la réponse à propos de l’orientation, mais je vois le lien qui convient pour bien comprendre l’orientation et supprimer la rotation forcée pour ios6.

http://www.disalvotech.com/blog/app-development/iphone/ios-6-rotation-solution/

Je pense que c'est une aide complète.

0
PeterParker