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

149

Avant iOS 8, nous utilisions le code ci-dessous en conjonction avec les méthodes de délégation supportedInterfaceOrientations et shouldAutoRotate pour forcer l'orientation de l'application à une orientation particulière. J'ai utilisé l'extrait de code ci-dessous pour faire pivoter l'application par programmation vers 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 vers 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. De plus, j'ai vu des réponses dans le débordement de pile où les gens ont suggéré que nous devrions 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 doit prendre en charge toutes les orientations de l'iPad et uniquement le portrait (bouton d'accueil vers le bas) sur l'iPhone.

  2. Contrôleur Second View - Il ne doit prendre en charge que le paysage dans toutes les conditions

  3. Contrôleur Third View - Il ne doit prendre en charge que le paysage dans toutes les conditions

Nous utilisons le contrôleur de navigation pour la navigation dans les pages. Depuis le premier contrôleur de vue, sur une action de clic de bouton, nous poussons le second sur la pile. Ainsi, lorsque le deuxième contrôleur de vue arrive, quelle que soit l'orientation de l'appareil, l'application doit se verrouiller uniquement en mode paysage.

Vous trouverez ci-dessous mes méthodes shouldAutorotateet supportedInterfaceOrientationsdans les deuxième et troisième contrôleurs de vue.

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

Existe-t-il une solution pour cela ou une meilleure façon de verrouiller un contrôleur de vue dans une orientation particulière pour iOS 8. Veuillez aider !!

Rashmi Ranjan mallick
la source
La mise en œuvre des méthodes que vous avez mentionnées dans le VC présenté devrait généralement fonctionner (du moins, c'est mon expérience dans iOS 8). Peut-être que votre configuration spécifique pose des problèmes?
Vladimir Gritsenko
Je peux peut-être clarifier un peu la question. Je modifierai légèrement la question.
Rashmi Ranjan mallick
@VladimirGritsenko: Veuillez vérifier maintenant. Je l'ai édité.
Rashmi Ranjan mallick
Le code de la question n'utilise pas la pile du contrôleur de navigation, mais plutôt la présentation modale, de sorte que ce que vous faites exactement n'est toujours pas clair. Je dirai que dans notre code, renvoyer YES de shouldAutoRotate et renvoyer les orientations souhaitées à partir de supportedInterfaceOrientations dans le VC présenté oriente correctement ce VC.
Vladimir Gritsenko
Eh bien, ce n'est pas vraiment un échec, c'est juste un grand changement de concept. Que ce soit un bon changement est un tout autre sujet.
Kegluneq

Réponses:

315

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:le contrôleur de vue présenté.

Sunny Shah
la source
61
Ce n'est pas une API privée. Il s'agit d'une utilisation non sécurisée des API. Vous n'utilisez pas de méthodes privées, mais utilisez des «choses internes». Si Apple modifie la valeur «orientation», cela échoue. Pire: si Apple change la signification de la valeur "orientation", vous ne savez pas ce que vous changez en définissant durement la valeur.
sonxurxo
4
Pour désactiver l' animation, mis [UIView setAnimationsEnabled:NO];en viewWillAppearet [UIView setAnimationsEnabled:YES];en viewDidAppear, liés: stackoverflow.com/a/6292506/88597
ohho
3
Bon hack, mais le problème avec ça, c'est que ce n'est pas le déclenchement de la didRotateFromInterfaceOrientation après avoir défini la nouvelle valeur d'orientation (soupir)
loretoparisi
2
Dans iOS 9.2, cela ne fait que changer d'orientation mais pas de verrouillage.
Mark13426
2
Pour tous ceux qui se comportent bien 90% du temps et buggy les 10% restants, appelez ceci après avoir réglé la clé d'orientation:[UINavigationController attemptRotationToDeviceOrientation];
Albert Renshaw
93

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

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

Donnez le pouvoir aux contrôleurs View!

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 supportedInterfaceOrientationsméthode ou vous pouvez remplacer shouldAutoRotatedans le contrôleur de vue que vous souhaitez verrouiller, sinon vous pouvez omettre les remplacements dans d'autres contrôleurs de vue dont vous souhaitez hériter du 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 vue 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 l'article de blog suivant si vous souhaitez en savoir plus sur la façon de contourner certains des problèmes:

Rotation de l'écran de verrouillage

Korey Hinton
la source
1
Je sais que c'est un très vieux message, mais où mettriez-vous le code d'extension?
dwinnbrown
7
Notation vers le bas pour une réponse Swift uniquement sur une question Objective-C.
Charlie Scott-Skinner
17
C'est une bonne solution pour Swift et ObjC. Je ne comprends pas pourquoi les gens votent. Vous avez l'idée et ensuite écrire du code est facile. Pourquoi se plaindre?
Zhao
2
@Krodak, dans les extensions, essayez de remplacer "-> Int" par "-> UIInterfaceOrientationMask". A fait l'affaire pour moi.
the_pantless_coder
2
L'idée et le code sont parfaits, je l'adore, mais il y a un problème lors de l'utilisation de UINavigationController, et du retour d'un UIViewController affiché en paysage à un qui doit être affiché en portrait. Des idées?
criseGriega
24

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];
}
Vincil Bishop
la source
3
Très utile, si l'appareil est déjà tourné et que vous devez faire pivoter votre contrôleur de vue
avdyushin
2
Très bonne réponse. Lorsqu'il est utilisé en combinaison avec la réponse acceptée, cela fonctionne bien pour moi à chaque fois dans Swift et iOS 9+.
AndyDunn
1
Bien que je pense que ce n'est pas la réponse à la question posée, cela m'a vraiment aidé.
Abdurrahman Mubeen Ali
21

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
}
Zipme
la source
4
Il semble que la réponse acceptée déclenche simplement un changement d'orientation vers le paysage. Ce que vous avez montré ici est comment forcer un contrôleur de vue à être uniquement en mode paysage, et ne pas affecter le contrôleur de vue de présentation (ce qui est exactement ce dont j'ai besoin). Merci.
Clifton Labrum
1
@CliftonLabrum avez-vous fait autre chose pour ne forcer que le paysage? En utilisant le même code, le contrôleur de vue peut toujours pivoter vers une autre orientation.
Crashalot le
J'ai réalisé plus tard que - vous avez raison. Je n'ai pas encore trouvé de solution.
Clifton Labrum
1
Cela a fonctionné pour moi. J'ai pu garder un seul contrôleur de vue en mode Portrait en utilisant ce code (en remplaçant Paysage par Portrait). +1
Mark Barrasso
Oui! Cela a fonctionné pour moi aussi dans Xcode 7.3 et Swift 2.2. Mais encore besoin de définir l'application func pour supportedInterfaceOrientationsForWindow dans AppDelegate.
charles.cc.hsu
16

Cela fonctionne pour moi dans Swift 2 iOS 8.x:

PS (cette méthode ne nécessite pas de remplacer les fonctions d'orientation comme shouldautorotate sur chaque viewController, juste une méthode sur AppDelegate)

Cochez la case "nécessite le plein écran" dans les informations générales de votre projet. entrez la description de l'image ici

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

var enableAllOrientation = false

Alors, mettez aussi cette func:

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 un 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
        }
    }
Alessandro Ornano
la source
très belle explication
Mihir Oza
11

Tout d'abord - c'est une mauvaise idée, en général, quelque chose ne va pas avec l'architecture de votre application, mais sh..t happens, si c'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")
    }
}

Que 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, l'appareil peut ne pas se mettre à jour à partir d'un tel appel, vous devrez donc peut-être faire comme suit

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

C'est tout

gbk
la source
9

Cela devrait fonctionner à partir d'iOS 6, mais je ne l'ai testé que sur iOS 8. Sous UINavigationController- classe et remplacez 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 y mettre en œuvre les méthodes.

Mojo66
la source
Je viens de tester cela sur mon application dans Xcode 8.2.1 sous iOS 10.0 et cela fonctionne. Mon menu de jeu est le premier écran et qui ne tourne pas; toutes les autres vues pivotent. Parfait! Je lui en ai donné un. Je n'avais besoin que de la fonction 'preferInterfaceOrientationForPresentation' donnée par Mojo66.
Philip Borges
9

Ceci est un retour aux commentaires de la réponse de Sid Shah , concernant la façon de désactiver les animations en utilisant:

[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];
}
ohho
la source
Comment puis-je utiliser cela pour Portrait.
Muju
6

Si vous utilisez navigationViewController, vous devez créer votre propre superclasse 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 votre appareil est en orientation portrait, votre SecondViewController apparaîtra en mode portrait.

Supposons que vous utilisez un storyboard. Vous devez créer un segue manuel ( Comment faire ) 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 fonction de rotation automatique.

Lau
la source
6

Sur Xcode 8les méthodes sont converties en propriétés, donc ce qui suit fonctionne 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
}
Ali Momen Sani
la source
Est-ce que cela verrouille l'orientation?
bnussey le
1
@bnussey Je voulais empêcher la rotation automatique et être toujours en portraitmode, quelle que soit l'orientation sur l'iPad, en shouldAutorotaterevenant vrai, j'ai réussi.
Ali Momen Sani le
4

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

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

- (BOOL) shouldAutorotate {
    return NO;
}   

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

Orientations possibles à partir de la documentation Apple :

UIInterfaceOrientationUnknown

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

UIInterfaceOrientationPortrait

L'appareil est en mode portrait, avec l'appareil en position verticale et le bouton d'accueil en bas.

UIInterfaceOrientationPortraitUpsideDown

L'appareil est en mode portrait mais à l'envers, avec l'appareil maintenu à la verticale et le bouton d'accueil en haut.

UIInterfaceOrientationPaysageGauche

L'appareil est en mode paysage, l'appareil tient à la verticale et le bouton d'accueil sur le côté gauche.

UIInterfaceOrientationPaysageDroite

L'appareil est en mode paysage, avec l'appareil tenu à la verticale et le bouton d'accueil sur le côté droit.

hoogw
la source
3

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 vers l'orientation appropriée avant le segue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "SomeSegue")
    {
        let value = UIInterfaceOrientation.Portrait.rawValue;
        UIDevice.currentDevice().setValue(value, forKey: "orientation")
    }
}
Misha
la source
Savez-vous si cela peut aider mon problème où le contrôleur de vue qui est affiché est en paysage pendant une seconde avant de tourner en portrait comme il devrait toujours l'être? la question est ici: stackoverflow.com/questions/30693964/…
dwinnbrown
3

La meilleure solution ci-dessus:

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

n'a pas fonctionné pour moi quand 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, j'ai donc dû l'ajouter comme ça)

guido
la source
Cela fonctionne, mais lorsque vous passez d'un contrôleur de vue paysage à un contrôleur de vue portrait, le contrôleur de vue qui doit s'afficher en portrait est brièvement affiché en paysage avant de tourner tout seul. si quelqu'un sait comment aider ma question est ici: stackoverflow.com/questions/30693964/…
dwinnbrown
@dwinnbrown at viewDidAppear, le contrôleur de vue est déjà visible. Peut-être essayer de viewDidLoad à la place?
Crashalot
@Crashalot J'ai maintenant corrigé ce problème. Veuillez consulter la réponse que j'ai marquée comme correcte.
dwinnbrown
@dwinnbrown le lien vers votre question est mort. mettre à jour? Merci!
Crashalot
@Crashalot la communauté l'a supprimé mais j'ai voté pour l'annuler. Je vous ferai savoir bientôt
dwinnbrown
3

[iOS9 +] Si quelqu'un a fait glisser tout le chemin vers le bas ici car aucune des solutions ci-dessus n'a fonctionné, et si vous présentez la vue que vous souhaitez changer d'orientation par suite, vous voudrez peut-être vérifier cela.

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

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

  • Ce changement ne fonctionne que lorsqu'il est combiné avec les solutions ci-dessus.
Goh
la source
2

Mes exigences sont

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

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

Tout d'abord, définissez supportedInterfaceOrientationsForWindowdansAppDelegate.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 principal, 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-classer 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
            }
        }
    }

Remplacez ces trois fonctions dans MyPlayerViewController.swift

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

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

Étant donné que l'utilisateur peut faire pivoter l'appareil en mode paysage vers la gauche ou vers la droite, nous devons définir la rotation automatique sur true.

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

Enfin, créez une MyPlayerViewControllerinstance 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 joueur avec le bon videoUrl, puis assignez votre joueur à playerViewController. Bon codage!

charles.cc.hsu
la source
2
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [UIViewController attemptRotationToDeviceOrientation];
}
Roman Solodyashkin
la source
1

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 UIViewControllerimplémentation:

- (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 autorisées de votre appareil sur «Paysage à gauche» dans les paramètres de votre projet (ou directement dans info.plist). Changez simplement l'orientation spécifique que vous souhaitez forcer si vous voulez autre chose queLandscapeLeft.

La clé pour moi était l' attemptRotationToDeviceOrientationappel viewWillAppear- sans cela, la vue ne tournerait pas correctement sans faire pivoter physiquement l'appareil.

ViperMav
la source
Méthode obsolète.
Saqib Omer
1

Selon la 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
}

Verrouiller à une orientation spécifique

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

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 objectif-c suivant github.com/GabLeRoux/RotationLockInTabbedViewChild avec un exemple de travail TabbedViewControlleroù une vue enfant est autorisée à tourner 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 racine telles que NavigationViewController. :)

La vue enfant verrouille l'orientation du parent

GabLeRoux
la source
0

Selon la solution montrée par @ sid-sha, vous devez tout mettre dans la viewDidAppear:méthode, sinon vous ne serez pas didRotateFromInterfaceOrientation:viré, 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"];
    }
}
Loretoparisi
la source
0

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.

Ensuite, la solution de Sunny Shah fonctionnerait dans votre XXViewControllerversion iOS:

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

Ceci est la fonction utilitaire pour trouver le plus haut 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
    }

}
duan
la source
0

Utilisez ceci pour verrouiller l'orientation du contrôleur de vue, testé sur IOS 9:

// Verrouiller l'orientation sur le paysage à droite

-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

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

J'ai le même problème et je perds tellement de temps pour cela. Alors maintenant, j'ai ma solution. Les paramètres de mon application ne prennent en charge que le portrait.Cependant, certains écrans de mon application ne doivent avoir que le paysage.Je le corrige en ayant une variable isShouldRotate à AppDelegate . Et la fonction chez AppDelegate :

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

Et enfin quand un ViewControllerA a besoin d'un état de paysage. Faites simplement cela: avant de pousser / présenter à ViewControllerA attribuez isShouldRotate à true . N'oubliez pas lorsque pop / ignorer ce contrôleur attribue isShouldRotate à false à viewWillDisappear .

Lee
la source
0

Pour moi, le VC de niveau supérieur nécessaire pour implémenter les remplacements d'orientation. L'utilisation de VC en bas de 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 dans mes tests.

bduhbya
la source
0

Il semble que même toi ici, il y a tellement de réponses que personne ne me suffisait. Je voulais forcer l'orientation, puis revenir à l'orientation de l'appareil mais[UIViewController attemptRotationToDeviceOrientation]; je n'ai tout simplement pas fonctionné. Ce qui a également compliqué le tout, c'est que j'ai ajouté shouldAutorotate à false en fonction d'une réponse et que je n'ai pas pu obtenir les effets souhaités pour une rotation correcte dans tous les scénarios.

Voici donc 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 je m'inscris à 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 à la vue, je me contente de revenir à n'importe quelle 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 le contrôleur de navigation doit déléguer à shouldAutorotate et supportedInterfaceOrientations, 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, fera encore plus d'extensions car ce n'est pas trop joli maintenant.

Renetik
la source