web-dev-qa-db-fra.com

Comment définir par programme l'orientation de l'appareil dans iOS 7?

Je travaille sur une application iPad, avec AutoLayout, où, si l'utilisateur active un certain mode (mode "heads-up"), je souhaite uniquement prendre en charge l'orientation portrait (ou portrait à l'envers) et, de plus, si paysage, je voudrais passer automatiquement en mode portrait.

Dans le contrôleur de vue de dessus, j'ai les éléments suivants:

- (NSUInteger) supportedInterfaceOrientations {
    if (self.modeHeadsUp) {
        return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}

- (BOOL) shouldAutorotate {
    return TRUE;
}

D'après les réponses que j'ai déjà vues ailleurs, la réponse est semble que je devrais utiliser "application setStatusBarOrientation". Par conséquent, dans la méthode où l'utilisateur a sélectionné le mode "heads-up", j'ai inclus:

    UIApplication *application = [UIApplication sharedApplication];
    [application setStatusBarOrientation:UIInterfaceOrientationPortrait
                                animated:YES];

Cependant, cela ne semble simplement rien faire. Bien que je puisse déplacer physiquement le périphérique pour le faire pivoter en portrait, il ne le fait pas automatiquement.

En fait, en mode paysage après avoir exécuté le code ci-dessus pour tenter de définir l'orientation par programme, lorsque j'interroge l'application "statusBarOrientation" avec le code suivant, il reste à "4" pour paysage: 

UIApplication *application = [UIApplication sharedApplication];
int orientation = [application statusBarOrientation];
self.movesTextView.text = [NSString stringWithFormat:@"ORIENTATION %d", orientation];

Il semblait que peut-être l'autolayout n'était pas déclenché avec setStatusBarOrientation, alors j'ai essayé d'ajouter ce code après, sans aucun effet:

    [super updateViewConstraints];
    [self.view updateConstraints];

Je me rends compte que Apple veut laisser l'orientation de l'appareil entre les mains de l'utilisateur. Toutefois, j'aimerais pouvoir prendre en charge le mode paysage lorsque vous n'êtes pas en mode "heads-up". 

Est-ce que je manque quelque chose pour pouvoir forcer le changement d'orientation?

70
John Stewart

Pour iOS 7 et 8:

Objectif c:

NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];

Swift 3+:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")

Je l'appelle dans - viewDidAppear:.

194
Sunny Shah

Utilisez ceci. Solution parfaite au problème d'orientation..ios7 et plus tôt

[[UIDevice currentDevice] setValue:
    [NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
        forKey:@"orientation"];
20
Arpan Dixit

Vous devez appeler attemptRotationToDeviceOrientation (UIViewController) pour que le système appelle votre supportedInterfaceOrientations lorsque la condition a changé.

10
snak
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"];

fonctionne, mais vous devez retourner DevraitAutoriser avec OUI dans votre contrôleur de vue

- (BOOL)shouldAutorotate
{
    return self.shouldAutoRotate;
}

Mais si vous faites cela, votre VC fera une autorotation si l’utilisateur fait pivoter le périphérique ... Je l’a donc changé en:

@property (nonatomic, assign) BOOL shouldAutoRotate;

- (BOOL)shouldAutorotate
{
    return self.shouldAutoRotate;
}

et j'appelle 

- (void)swithInterfaceOrientation:(UIInterfaceOrientation)orientation
{
    self.rootVC.shouldAutoRotate = YES;

    NSNumber *value = [NSNumber numberWithInt: orientation];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}

pour forcer une nouvelle orientation avec un clic de bouton . Pour revenir en arrière devraitAutoRotate à NO, j'ai ajouté à mon rootVC

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    self.shouldAutoRotate = NO;
}

PS: Cette solution de contournement fonctionne également dans tous les simulateurs.

4
Rikco

Cela fonctionne pour moi sur Xcode 6 & 5.

- (BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return (UIInterfaceOrientationMaskPortrait);
}
4
SamSmart

La seule façon qui a fonctionné pour moi est de présenter un contrôleur de vue modal factice.

UIViewController* dummyVC = [[UIViewController alloc] init];
dummyVC.view = [[UIView alloc] init];
[self presentModalViewController:dummyVC animated:NO];
[self dismissModalViewControllerAnimated:NO];

Il sera demandé à votre VC des orientations d’interface mises à jour lorsque le contrôleur de vue modale est désactivé.

Ce qui est curieux, c’est que UINavigationController fait exactement cela lorsqu’il pousse/éclate des contrôleurs de vue enfant avec différentes orientations d’interface supportées (testé sur iOS 6.1, 7.0).

3
kjam

Cette solution vous permet de forcer une certaine orientation d'interface en remplaçant temporairement la valeur UIDevice.current.orientation, puis en demandant au système de faire pivoter l'interface pour qu'elle corresponde à la rotation du périphérique:

Important: Ceci est un hack et pourrait cesser de fonctionner à tout moment

Ajoutez les éléments suivants dans le contrôleur de vue racine de votre application:

class RootViewController : UIViewController {
    private var _interfaceOrientation: UIInterfaceOrientation = .portrait
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return UIInterfaceOrientationMask(from: _interfaceOrientation) }
    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return _interfaceOrientation }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Register for notifications
        NotificationCenter.default.addObserver(self, selector: #selector(RootViewController.handleInterfaceOrientationChangeRequestedNotification(_:)), name: .interfaceOrientationChangeRequested, object: nil)
    }

    deinit { NotificationCenter.default.removeObserver(self) }

    func handleInterfaceOrientationChangeRequestedNotification(_ notification: Notification) {
        guard let interfaceOrientation = notification.object as? UIInterfaceOrientation else { return }
        _interfaceOrientation = interfaceOrientation
        // Set device orientation
        // Important:
        // • Passing a UIDeviceOrientation here doesn't work, but passing a UIInterfaceOrientation does
        // • This is a hack, and could stop working at any moment
        UIDevice.current.setValue(interfaceOrientation.rawValue, forKey: "orientation")
        // Rotate the interface to the device orientation we just set
        UIViewController.attemptRotationToDeviceOrientation()
    }
}

private extension UIInterfaceOrientationMask {

    init(from interfaceOrientation: UIInterfaceOrientation) {
        switch interfaceOrientation {
        case .portrait: self = .portrait
        case .landscapeLeft: self = .landscapeLeft
        case .landscapeRight: self = .landscapeRight
        case .portraitUpsideDown: self = .portraitUpsideDown
        case .unknown: self = .portrait
        }
    }
}

extension Notification.Name {
    static let interfaceOrientationChangeRequested = Notification.Name(rawValue: "interfaceOrientationChangeRequested")
}

Assurez-vous que toutes les orientations de l'interface sont vérifiées sous "Informations de déploiement":

 Interface Orientations

Demander les changements d'orientation de l'interface là où vous en avez besoin:

NotificationCenter.default.post(name: .interfaceOrientationChangeRequested, object: UIInterfaceOrientation.landscapeRight)
3
Niels
  1. Ajouter cette déclaration dans AppDelegate.h

    //whether to allow cross screen marker 
    @property (nonatomic, assign) allowRotation BOOL;
    
  2. Notez cette section de code dans AppDelegate.m

    - (UIInterfaceOrientationMask) application: (UIApplication *) supportedInterfaceOrientationsForWindow: application (UIWindow *) window {
        If (self.allowRotation) {
            UIInterfaceOrientationMaskAll return;
        }
        UIInterfaceOrientationMaskPortrait return;
    }
    
  3. Changer la propriété allowRotation de l'application déléguée

2
niuNaruto

Si vous avez un UIViewController qui doit rester en mode Portrait, ajoutez simplement ce remplacement et vous êtes prêt.

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}

La meilleure partie est qu'il n'y a pas d'animation lorsque cette vue est affichée, elle est déjà dans la bonne orientation.

2
Torre Lasley

Si vous souhaitez verrouiller la vue principale de votre application sur Portrait, mais que vous souhaitez ouvrir des vues contextuelles en mode paysage et que vous utilisez tabBarController en tant que rootViewController en tant que moi, vous pouvez utiliser ce code sur votre AppDelegate.

AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UITabBarController *tabBarController;

@end

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Create a tab bar and set it as root view for the application
    self.tabBarController = [[UITabBarController alloc] init];
    self.tabBarController.delegate = self;
    self.window.rootViewController = self.tabBarController;

    ...
}

- (NSUInteger)tabBarControllerSupportedInterfaceOrientations:(UITabBarController *)tabBarController
{
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)tabBarControllerPreferredInterfaceOrientationForPresentation:(UITabBarController *)tabBarController
{
    return UIInterfaceOrientationPortrait;
}

Il fonctionne très bien.

Dans votre viewController que vous souhaitez afficher en paysage, vous utilisez simplement les éléments suivants:

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate {
    return YES;
}

Le UINavigationController de base doit avoir le rappel ci-dessous afin que les éléments enfants puissent décider de l'orientation qu'ils souhaitent.

-(NSUInteger)supportedInterfaceOrientations {
    UIViewController *topVC = self.topViewController;
    return topVC.supportedInterfaceOrientations;
}

-(BOOL)shouldAutorotate {
   UIViewController *topVC = self.topViewController;
   return [topVC shouldAutorotate];
}
1
Ekra

voici un exemple PLEIN DE TRAVAIL pour iOS 7, 8, 9, 10 comment changer l'orientation de l'application en fonction de son opposé

Objectif c

- (void)flipOrientation
{
    NSNumber *value;
    UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if(UIInterfaceOrientationIsPortrait(currentOrientation))
    {
        if(currentOrientation == UIInterfaceOrientationPortrait)
        {
            value = [NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown];
        }
        else //if(currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
        {
            value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
        }
    }
    else
    {
        if(currentOrientation == UIInterfaceOrientationLandscapeRight)
        {
            value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
        }
        else //if(currentOrientation == UIInterfaceOrientationLandscapeLeft)
        {
            value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
        }
    }
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    [UIViewController attemptRotationToDeviceOrientation];
}

Swift 3

func flipOrientation() -> Void
{
    let currentOrientation : UIInterfaceOrientation = UIApplication.shared.statusBarOrientation
    var value : Int = 0;
    if(UIInterfaceOrientationIsPortrait(currentOrientation))
    {
        if(currentOrientation == UIInterfaceOrientation.portrait)
        {
            value = UIInterfaceOrientation.portraitUpsideDown.rawValue
        }
        else //if(currentOrientation == UIInterfaceOrientation.portraitUpsideDown)
        {
            value = UIInterfaceOrientation.portrait.rawValue
        }
    }
    else
    {
        if(currentOrientation == UIInterfaceOrientation.landscapeRight)
        {
            value = UIInterfaceOrientation.landscapeLeft.rawValue
        }
        else //if(currentOrientation == UIInterfaceOrientation.landscapeLeft)
        {
            value = UIInterfaceOrientation.landscapeRight.rawValue
        }
    }
    UIDevice.current.setValue(value, forKey: "orientation")
    UIViewController.attemptRotationToDeviceOrientation()
}
1
ddb

J'étais dans un problème similaire à vous. J'ai besoin de verrouiller l'orientation de l'appareil pour certains écrans (comme Login) et de permettre la rotation des autres.

Après quelques changements et après quelques réponses ci-dessous, je l'ai fait par:

  • Activer toutes les orientations dans Info.plist du projet.

 enter image description here

  • Désactivation de l'orientation dans les ViewControllers où j'ai besoin que le périphérique ne tourne pas, comme dans l'écran de connexion dans mon cas. J'avais besoin de remplacer la méthode shouldAutorotate dans ce VC:

-(BOOL)shouldAutorotate{ return NO; }

J'espère que cela fonctionnera pour vous.

1
David de Tena

Si vous souhaitez uniquement le mode portrait, dans iOS 9 (Xcode 7), vous pouvez: 

  • Aller sur Info.plist
  • Sélectionnez l'élément "Orientations d'interface prises en charge"
  • Supprimer "Paysage (bouton d'accueil de gauche)" et "Paysage (bouton d'accueil de droite)"

 enter image description here

1
Danilo Raspa

Cela m'a fonctionné parfaitement ....

NSNumber *value = [NSNumber numberWithInt:UIDeviceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
0
Prasanna

Pour ceux qui, comme moi, avaient du mal à obtenir @Sunny Shah, acceptaient de travailler sur iPad. Vous devez activer la case à cocher "Nécessite le plein écran" dans les paramètres du projet. Notez que cela empêchera votre application de fonctionner en mode multitâche, ce qui peut être acceptable ou non.

 enter image description here 

0
leandrodemarco

Essayez ceci avec votre code.

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

une fois que l'utilisateur sélectionne une option, appelez cette méthode, car il peut être en mode paysage, puis il ne peut définir que le mode portrait dans le même contrôleur de vue. La vue doit donc automatiquement être déplacée en mode portrait.

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
0
Charan Giri