web-dev-qa-db-fra.com

Comment forcer l'orientation du contrôleur de vue dans iOS 8?

Avant iOS 8, nous utilisions le code ci-dessous conjointement aux méthodes supportedInterfaceOrientations et shouldAutoRotate pour imposer l'orientation de l'application à une orientation particulière. J'ai utilisé l'extrait de code ci-dessous pour faire pivoter l'application par programme selon l'orientation souhaitée. Tout d'abord, je change l'orientation de la barre d'état. Ensuite, il suffit de présenter et de supprimer immédiatement une vue modale pour faire pivoter la vue selon l'orientation souhaitée.

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];

Mais cela échoue dans iOS 8. En outre, j’ai vu quelques réponses concernant le débordement de pile où des personnes ont suggéré de toujours éviter cette approche à partir d’iOS 8.

Pour être plus précis, mon application est un type d'application universel. Il y a trois contrôleurs au total.

  1. Contrôleur First View - Il devrait prendre en charge toutes les orientations dans iPad et uniquement en mode portrait (bouton d'accueil enfoncé) dans iPhone.

  2. Contrôleur Second View - Il ne devrait supporter que le droit de paysage dans toutes les conditions

  3. Third View controller - Il ne devrait supporter que le droit de paysage dans toutes les conditions

Nous utilisons le contrôleur de navigation pour la navigation de page. À partir du premier contrôleur de vue, lors d’une action sur un clic de bouton, nous poussons le second sur la pile. Ainsi, lorsque le second contrôleur de vue arrive, quelle que soit l'orientation du périphérique, l'application ne doit être verrouillée qu'en mode paysage.

Ci-dessous, mes méthodes shouldAutorotate et supportedInterfaceOrientations dans les deuxième et troisième contrôleurs de vue.

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

Existe-t-il une solution à ce problème ou un meilleur moyen de verrouiller un contrôleur de vue avec une orientation particulière pour iOS 8. Aidez-nous!

142

Pour iOS 7 - 10:

Objectif c:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];

Swift 3:

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

Appelez-le simplement dans - viewDidAppear: du contrôleur de vue présenté.

300
Sunny Shah

La rotation d'orientation est un peu plus compliquée si vous êtes à l'intérieur de UINavigationController ou UITabBarController. Le problème est que si un contrôleur de vue est intégré à l'un de ces contrôleurs, le contrôleur de navigation ou de barre de tabulation est prioritaire et prend les décisions relatives à l'autorotation et aux orientations prises en charge.

J'utilise les 2 extensions suivantes sur UINavigationController et UITabBarController afin que les contrôleurs de vue intégrés à l'un de ces contrôleurs puissent prendre les décisions.

Donnez le pouvoir aux contrôleurs de vue!

Swift 2.3

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

extension UITabBarController {
    public override func supportedInterfaceOrientations() -> Int {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

Swift 3

extension UINavigationController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
    }
}

extension UITabBarController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

Vous pouvez maintenant remplacer la méthode supportedInterfaceOrientations ou shouldAutoRotate dans le contrôleur de vue que vous souhaitez verrouiller, sinon vous pouvez omettre les remplacements dans les autres contrôleurs de vue dont vous souhaitez hériter le comportement d'orientation par défaut spécifié dans le plist de votre application

Désactiver la rotation

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

Verrouiller à une orientation spécifique

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

En théorie, cela devrait fonctionner pour toutes les hiérarchies de contrôleurs de vues complexes, mais j'ai remarqué un problème avec UITabBarController. Pour une raison quelconque, il souhaite utiliser une valeur d'orientation par défaut. Consultez le blog suivant si vous souhaitez en savoir plus sur la résolution de certains problèmes:

rotation de l'écran de verrouillage

91
Korey Hinton

C'est ce qui a fonctionné pour moi:

https://developer.Apple.com/library//ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//Apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation =

Appelez-le dans votre méthode viewDidAppear :.

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [UIViewController attemptRotationToDeviceOrientation];
}
23
Vincil Bishop

J'ai trouvé que s'il s'agit d'un contrôleur de vue présenté, vous pouvez remplacer preferredInterfaceOrientationForPresentation

Rapide:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

override func shouldAutorotate() -> Bool {
  return false
}
20
Zipme

Cela me permet de travailler dans Swift 2 iOS 8.x:

PS (cette méthode n’a pas besoin de surcharger les fonctions d’orientation telles que shouldautorotate sur chaque viewController, une seule méthode sur AppDelegate)

Cochez la case "nécessite un plein écran" dans les informations générales de votre projet. enter image description here

Donc, sur AppDelegate.Swift, créez une variable:

var enableAllOrientation = false

Alors, mettez aussi cette fonction:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if (enableAllOrientation == true){
            return UIInterfaceOrientationMask.All
        }
        return UIInterfaceOrientationMask.Portrait
}

Ainsi, dans chaque classe de votre projet, vous pouvez définir cette variable dans viewWillAppear:

override func viewWillAppear(animated: Bool)
{
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.enableAllOrientation = true
}

Si vous devez faire des choix en fonction du type d'appareil, vous pouvez le faire:

override func viewWillAppear(animated: Bool)
    {
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        switch UIDevice.currentDevice().userInterfaceIdiom {
        case .Phone:
        // It's an iPhone
           print(" - Only portrait mode to iPhone")
           appDelegate.enableAllOrientation = false
        case .Pad:
        // It's an iPad
           print(" - All orientation mode enabled on iPad")
           appDelegate.enableAllOrientation = true
        case .Unspecified:
        // Uh, oh! What could it be?
           appDelegate.enableAllOrientation = false
        }
    }
15
Alessandro Ornano

Tout d’abord, c’est une mauvaise idée. En général, il y a quelque chose qui ne va pas avec l’architecture de votre application, mais, sh..t happens, si tel est le cas, vous pouvez essayer de faire quelque chose comme ci-dessous:

final class OrientationController {

    static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]

    // MARK: - Public

    class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
        OrientationController.allowedOrientation = [orientationIdiom]
    }

    class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
        var mask:UIInterfaceOrientationMask = []
        switch orientation {
            case .unknown:
                mask = [.all]
            case .portrait:
                mask = [.portrait]
            case .portraitUpsideDown:
                mask = [.portraitUpsideDown]
            case .landscapeLeft:
                mask = [.landscapeLeft]
            case .landscapeRight:
                mask = [.landscapeRight]
        }

        OrientationController.lockOrientation(mask)

        UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
    }
}

Ensuite, dans AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // do stuff
    OrientationController.lockOrientation(.portrait)
    return true
}

// MARK: - Orientation

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return OrientationController.allowedOrientation
}

Et chaque fois que vous souhaitez changer d'orientation, procédez comme suit:

OrientationController.forceLockOrientation(.landscapeRight)

Remarque: Parfois, le périphérique peut ne pas être mis à jour à partir de cet appel. Vous devrez peut-être procéder comme suit.

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)

C'est tout

10
gbk

Cela devrait fonctionner à partir d'iOS 6, mais je ne l'ai testé que sur iOS 8. Sous-classe UINavigationController et remplacer les méthodes suivantes:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}

Ou demandez au contrôleur de vue visible

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}

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

et mettre en œuvre les méthodes là-bas.

9
Mojo66

Ceci est un retour aux commentaires dans réponse de Sid Shah , concernant la désactivation des animations à l'aide de:

[UIView setAnimationsEnabled:enabled];

Code:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:NO];
    [UIView setAnimationsEnabled:NO];

    // Stackoverflow #26357162 to force orientation
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:NO];
    [UIView setAnimationsEnabled:YES];
}
9
ohho

Sur Xcode 8, les méthodes sont converties en propriétés. Par conséquent, les méthodes suivantes fonctionnent avec Swift:

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}

override public var shouldAutorotate: Bool {
    return true
}
6
Ali Momen Sani

Si vous utilisez navigationViewController, vous devez créer votre propre super-classe pour cela et remplacer:

- (BOOL)shouldAutorotate {
  id currentViewController = self.topViewController;

  if ([currentViewController isKindOfClass:[SecondViewController class]])
    return NO;

  return YES;
}

cela désactivera la rotation dans SecondViewController mais si vous poussez votre SecondViewController lorsque Si l'appareil est en orientation portrait, votre SecondViewController apparaîtra en mode portrait.

Supposons que vous utilisez le storyboard. Vous devez créer un segue manuel ( Comment ) et dans votre méthode "onClick":

- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
  NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
  [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
  [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}

Cela forcera l'orientation paysage avant que votre superclasse ne désactive la fonctionnalité d'autorotation.

6
Lau

J'ai essayé de nombreuses solutions, mais celle qui a fonctionné est la suivante:

Il n'est pas nécessaire de modifier le info.plist dans ios 8 et 9.

- (BOOL) shouldAutorotate {
    return NO;
}   

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}

Orientations possibles à partir de la Apple Documentation :

UIInterfaceOrientationUnknown

L'orientation de l'appareil ne peut pas être déterminée.

UIInterfaceOrientationPortrait

L’appareil est en mode portrait, l’appareil étant maintenu à la verticale et le bouton principal situé en bas.

UIInterfaceOrientationPortraitUpsideDown

L'appareil est en mode portrait mais à l'envers, avec l'appareil maintenu en position verticale et le bouton principal situé en haut.

UIInterfaceOrientationLandscapeLeft

L’appareil est en mode paysage, l’appareil étant maintenu droit et le bouton principal situé à gauche.

UIInterfaceOrientationLandscapeRight

L’appareil est en mode paysage, l’appareil maintenu en position verticale et le bouton principal situé à droite.

4
hoogw

La combinaison des réponses Sids et Koreys a fonctionné pour moi.

Extension du contrôleur de navigation:

extension UINavigationController {
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

Puis désactivation de la rotation sur la vue unique

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

Et en tournant à l'orientation appropriée avant la segue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "SomeSegue")
    {
        let value = UIInterfaceOrientation.Portrait.rawValue;
        UIDevice.currentDevice().setValue(value, forKey: "orientation")
    }
}
3
Misha

[iOS9 +] Si quelqu'un traînait jusqu'au bout car aucune des solutions ci-dessus ne fonctionnait, et si vous présentiez la vue que vous souhaitez changer d'orientation par séquence, vous voudrez peut-être vérifier ceci.

Vérifiez le type de présentation de votre segue. Le mien était "sur le contexte actuel". Lorsque je l'ai changé en plein écran, cela a fonctionné.

Grâce à @GabLeRoux, j'ai trouvé cette solution.

  • Cela ne fonctionne que lorsque combiné aux solutions ci-dessus.
2
Goh

Mes exigences sont

  1. verrouiller toutes les vues en mode portrait
  2. utiliser AVPlayerViewController pour lire la vidéo

Lors de la lecture d'une vidéo, s'il s'agit d'un paysage, laissez l'écran pivoter à droite et à gauche. S'il s'agit d'un portrait, verrouillez la vue en mode portrait uniquement.

Tout d’abord, définissez supportedInterfaceOrientationsForWindow dans AppDelegate.Swift

var portrait = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if portrait {
        return .Portrait
    } else {
        return .Landscape
    }
}

Deuxièmement, dans votre contrôleur de vue principale, définissez les fonctions suivantes

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    print("\(#function)")
    return .Portrait
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return .Portrait
}

override func shouldAutorotate() -> Bool {
    return false
}

Ensuite, vous devez sous-classe AVPlayerViewController

class MyPlayerViewController: AVPlayerViewController {

    var size: CGSize?

    var supportedOrientationMask: UIInterfaceOrientationMask?
    var preferredOrientation: UIInterfaceOrientation?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let size = size {
            if size.width > size.height {
                self.supportedOrientationMask =[.LandscapeLeft,.LandscapeRight]
                self.preferredOrientation =.LandscapeRight
            } else {
                self.supportedOrientationMask =.Portrait
                self.preferredOrientation =.Portrait
            }
        }
    }

Remplacer ces trois fonctions dans MyPlayerViewController.Swift

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return self.supportedOrientationMask!
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return self.preferredOrientation!
}

Parce que l'utilisateur peut faire pivoter paysage de l'appareil à gauche ou à droite, nous devons définir la rotation automatique sur true

override func shouldAutorotate() -> Bool {
    return true
}

Enfin, créez une instance MyPlayerViewController dans votre contrôleur de vue et définissez la valeur de la taille de la propriété.

let playerViewController = MyPlayerViewController()

// Get the thumbnail  
let thumbnail = MyAlbumFileManager.sharedManager().getThumbnailFromMyVideoMedia(......)

let size = thumbnail?.size
playerViewController.size = size

Initiez votre lecteur avec la variable videoUrl appropriée, puis affectez-le à playerViewController. Bon codage!

2
charles.cc.hsu

La solution supérieure ci-dessus:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

cela ne fonctionnait pas pour moi lorsque je l'ai appelé dans viewDidAppear du contrôleur de vue présenté. Cependant, cela a fonctionné lorsque je l'ai appelé dans preparForSegue dans le contrôleur de vue de présentation.

(Désolé, pas assez de points de réputation pour commenter cette solution, je devais donc l'ajouter comme ça)

2
guido
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [UIViewController attemptRotationToDeviceOrientation];
}
2
Roman Solodyashkin

Selon réponse de Korey Hinton

Swift 2.2:

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return visibleViewController!.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController!.shouldAutorotate()
    }
}


extension UITabBarController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

Désactiver la rotation

override func shouldAutorotate() -> Bool {
    return false
}

Verrouillage sur une orientation spécifique

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

J'ai essayé quelques solutions ici et la chose importante à comprendre est que c'est le contrôleur de vue racine qui déterminera s'il tournera ou non.

J'ai créé le projet objective-c suivant github.com/GabLeRoux/RotationLockInTabbedViewChild avec un exemple de travail de TabbedViewController où une vue enfant est est autorisée à pivoter et l’autre vue enfant est verrouillée en portrait.

Ce n'est pas parfait, mais cela fonctionne et la même idée devrait fonctionner pour d'autres types de vues telles que NavigationViewController. :)

Child view locks parent orientation

1
GabLeRoux

Il semble encore y avoir un débat sur la meilleure façon d'accomplir cette tâche, alors j'ai pensé partager mon approche (de travail). Ajoutez le code suivant dans votre implémentation UIViewController:

- (void) viewWillAppear:(BOOL)animated
{
    [UIViewController attemptRotationToDeviceOrientation];
}

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

-(BOOL)shouldAutorotate
{
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft;
}

Pour cet exemple, vous devrez également définir les orientations de périphérique autorisées sur "Paysage gauche" dans les paramètres de votre projet (ou directement dans info.plist). Changez simplement l’orientation spécifique que vous voulez forcer si vous voulez autre chose que LandscapeLeft.

La clé pour moi était l'appel attemptRotationToDeviceOrientation dans viewWillAppear - sans quoi la vue ne pourrait pas pivoter correctement sans une rotation physique de l'appareil.

0
ViperMav

J'ai le même problème et je perds beaucoup de temps à le résoudre. Alors maintenant, j'ai ma solution. Mon paramètre d'application est uniquement compatible avec Portrait seulement. Cependant, certains écrans de mon application n'ont besoin que de paysage. Je le répare en ayant une variable isShouldRotate à . Et la fonction sur AppDelegate :

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    if isShouldRotate == true {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

Et enfin, lorsqu'un ViewControllerA a besoin d'un état paysage. Faites juste cela: avant Push/present à ViewControllerA attribue isShouldRotate à true . N'oubliez pas que lorsque le menu contextuel est affiché/supprimé, le contrôleur affecte isShouldRotate à false à viewWillDisappear .

0
lee

Selon la solution montrée par @ sid-sha, vous devez tout mettre dans la méthode viewDidAppear:, sinon vous ne obtiendrez pas le didRotateFromInterfaceOrientation: renvoyé, donc quelque chose comme:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
        interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        NSNumber *value = [NSNumber numberWithInt:interfaceOrientation];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}
0
loretoparisi

On dirait que même toi, ici, a tellement de réponses que personne ne me suffisait. Je voulais forcer l’orientation, puis je revenais à l’orientation des appareils, mais [UIViewController attemptRotationToDeviceOrientation]; ne fonctionnait tout simplement pas. Ce qui a également compliqué les choses, c’est que j’ai ajouté shouldAutorotate à false sur la base d’une réponse et que je ne pouvais pas faire en sorte que les effets souhaités soient correctement reconvertis dans tous les scénarios.

Alors voici ce que j'ai fait:

Avant de pousser le contrôleur en appel dans son constructeur init, ceci:

_userOrientation = UIDevice.currentDevice.orientation;
[UIDevice.currentDevice setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
[self addNotificationCenterObserver:@selector(rotated:)
                               name:UIDeviceOrientationDidChangeNotification];

Je sauvegarde donc la dernière orientation de l'appareil et m'inscris pour l'événement de changement d'orientation. L'événement de changement d'orientation est simple:

- (void)rotated:(NSNotification*)notification {
    _userOrientation = UIDevice.currentDevice.orientation;
}

Et à ma vue, je me contente de revenir à l’orientation que j’ai en tant qu’utilisateurOreintation:

- (void)onViewDismissing {
    super.onViewDismissing;
    [UIDevice.currentDevice setValue:@(_userOrientation) forKey:@"orientation"];
    [UIViewController attemptRotationToDeviceOrientation];
}

Et cela doit être là aussi:

- (BOOL)shouldAutorotate {
    return true;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

Et aussi contrôleur de navigation doit déléguer à devraitAutorotate et supportéInterfaceOrientations, mais que la plupart des gens ont déjà je crois.

PS: Désolé, j'utilise des extensions et des classes de base, mais les noms sont assez significatifs, donc le concept est compréhensible, il créera encore plus d’extensions car il n’est plus très joli à l’heure actuelle.

0
Renetik

Ma solution

Dans AppDelegate:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if let topController = UIViewController.topMostViewController() {
        if topController is XXViewController {
            return [.Portrait, .LandscapeLeft]
        }
    }
    return [.Portrait]
}

XXViewController est le ViewController que vous souhaitez prendre en charge en mode Paysage.

Alors la solution Sunny Shah fonctionnerait dans votre XXViewController sur n'importe quelle version iOS:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

C’est la fonction utilitaire permettant de trouver le plus élevé des ViewController.

extension UIViewController {

    /// Returns the current application's top most view controller.
    public class func topMostViewController() -> UIViewController? {
        let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
        return self.topMostViewControllerOfViewController(rootViewController)
    }



    /// Returns the top most view controller from given view controller's stack.
    class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
        // UITabBarController
        if let tabBarController = viewController as? UITabBarController,
           let selectedViewController = tabBarController.selectedViewController {
            return self.topMostViewControllerOfViewController(selectedViewController)
        }

        // UINavigationController
        if let navigationController = viewController as? UINavigationController,
           let visibleViewController = navigationController.visibleViewController {
            return self.topMostViewControllerOfViewController(visibleViewController)
        }

        // presented view controller
        if let presentedViewController = viewController?.presentedViewController {
            return self.topMostViewControllerOfViewController(presentedViewController)
        }

        // child view controller
        for subview in viewController?.view?.subviews ?? [] {
            if let childViewController = subview.nextResponder() as? UIViewController {
                return self.topMostViewControllerOfViewController(childViewController)
            }
        }

        return viewController
    }

}
0
duan

Pour moi, le niveau supérieur VC devait mettre en œuvre les substitutions d'orientation. L'utilisation de VC dans la pile n'aura aucun effet si le VC supérieur n'est pas implémenté.

VC-main
    |
    -> VC 2
        |
        -> VC 3

Seul VC-Main est écouté, essentiellement lors de mes tests.

0
bduhbya

Utilisez-le pour verrouiller l’orientation du contrôleur de vue, testé sur IOS 9:

// Verrouille l'orientation en paysage à droite

-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
    return UIInterfaceOrientationMaskLandscapeRight;
}
0
robegamesios