web-dev-qa-db-fra.com

Comment maintenir l'orientation du contrôleur de présentation lorsque vous quittez le contrôleur de vue modal?

J'ai cette application sur laquelle je travaille et j'ai besoin de TOUS mes contrôleurs de vue, mais l'un d'entre eux doit être en portrait… .. Le contrôleur de vue unique qui est spécial en a besoin pour pouvoir pivoter dans l'orientation du téléphone.

Pour ce faire, je le présente de manière modale (non intégré à un NavigationController)

Donc (par exemple) ma structure est comme ceci:

  • fenêtre - Portrait
    • contrôleur de vue racine (UINavigationController - Portrait)
      • contrôleur de vue d'accueil (UIViewController - Portrait)
        • détails view controller (UIViewController - Portrait)
        • .
        • .
        • contrôleur de vue modale (UIVIewController - All)

Maintenant, chaque fois que je rejette mon contrôleur de vue modal en position paysage, mon contrôleur de vue parent est ÉGALEMENT pivoté même s'il ne prend pas en charge cette orientation.

Tous les UIViewControllers et UINavigaionControllers de l'application héritent des mêmes classes générales dans lesquelles ces méthodes sont implémentées:

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

Mon contrôleur de vue modale redéfinit cette méthode et se présente comme suit:

override func supportedInterfaceOrientations() -> Int
{
    return Int(UIInterfaceOrientationMask.All.toRaw())
}

Mise à jour 1

Il semblerait que cela ne se produise que sur iOS8 Bêta ........ Quelqu'un sait-il si quelque chose a changé en ce qui concerne la rotation du contrôleur de vue ou s'agit-il simplement d'un bug de la version bêta?

32
Mihai Fratu
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
    SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;

    if (secondController.isPresented)
        return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}

Et pour Swift

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {

    if self.window?.rootViewController?.presentedViewController? is SecondViewController {

        let secondController = self.window!.rootViewController.presentedViewController as SecondViewController

        if secondController.isPresented {
            return Int(UIInterfaceOrientationMask.All.toRaw());
        } else {
            return Int(UIInterfaceOrientationMask.Portrait.toRaw());
        }
    } else {
        return Int(UIInterfaceOrientationMask.Portrait.toRaw());
    }

}

Pour plus de détails, consultez ce lien link

18
ZaEeM ZaFaR

Je rencontre le même problème avec une application et après des jours d’expérimentation, j’ai trouvé une solution qui n’est pas très jolie mais qui fonctionne pour le moment. J'utilise la méthode déléguée application:supportedInterfaceOrientationsForWindow: dans l'appdelegate. 

J'ai créé un projet test et l'ai mis ici sur github (avec un GIF indiquant le résultat ...)

// remarque: ce n'est pas dans Swift mais j'espère que ça aide quand même

7
jules

Après de nombreuses expériences, je suis convaincu qu'il s'agit d'une "fonctionnalité" d'iOS 8.

Si vous y réfléchissez, cela semble parfaitement logique, car cela se produit depuis longtemps.

  • Dans iOS 4, par exemple, il était possible de forcer la rotation des applications lors de la modification des contrôleurs de vue dans un contrôleur à barres de tabulation et un contrôleur de navigation, ainsi que lors de la présentation/suppression d'un contrôleur.

  • Ensuite, sous iOS 6, il est devenu impossible de forcer la rotation des applications sauf lors de la présentation/suppression d'un contrôleur de vue (comme je l'expliquais dans de nombreuses réponses, telles que this celui ).

  • Maintenant, dans iOS 8, je suppose qu'il sera impossible de forcer la rotation de l'application (sauf lors du lancement). Elle peut préférer une certaine orientation, de sorte qu’une fois dans cette orientation, elle y reste, mais elle ne peut pas forcer l’application à suivre cette orientation.

    Au lieu de cela, votre contrôleur de vue doit "s'adapter". Plusieurs vidéos de la WWDC 2014 se concentrant sur «l'adaptation», et je commence maintenant à comprendre que c'est l'une des raisons pour lesquelles c'est si important.

    EDIT: Dans la graine 4, il semble que cette fonctionnalité (forçant la rotation sur présentation et le renvoi) revienne!

4
matt

Nous avons une application déployée avec un contrôleur de paysage qui présente un contrôleur de vue en mode portrait uniquement. A été examiné par Apple sur iOS 8. Nous ne substituons que les interfaces supportedInterfaceOrientations.

Il convient de noter que nous avons trouvé de nombreuses différences entre les versions 3, 4 et 5. En fin de compte, nous avons dû attendre le GM avant de faire un effort concerté pour mettre à jour notre application pour iOS 8.

Dans iOS 8, vous devez faire très attention à ne pas le faire:

[self dismissViewControllerAnimated:YES completion:nil]
[self presentViewController:vc animated:YES completion:nil]

Si le vc sortant est en mode portrait et que le vant entrant est en paysage, il se peut que certains cadres de vue soient très gâchés. Présentez plutôt le vc entrant dans le bloc d'achèvement de l'appel de licenciement.

[self dismissViewControllerAnimated:YES completion:^{
    [self presentViewController:vc animated:YES completion:nil]
}];
3
Airsource Ltd

C'est en fait plus facile et peut être fait sans propriétés supplémentaires (voici un exemple avec AVPlayerViewController):

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        if ([self.window.rootViewController.presentedViewController isKindOfClass: [AVPlayerViewController class]])
            return self.window.rootViewController.presentedViewController.isBeingDismissed ? 
            UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskAll;
        else
            return UIInterfaceOrientationMaskPortrait;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}
2
xfyre

Question géniale et réponse géniale fournie par @ZaEeM ZaFaR ! La combinaison de sa réponse avec ceci m'a amené à une solution géniale et géniale. 

L'inconvénient de la première réponse est que vous devez gérer la variable isPresented dans chaque contrôleur de vue permettant des rotations. En outre, vous devez développer la vérification et attribuer supportedInterfaceOrientationsForWindow pour chaque vc permettant la rotation. 

L'inconvénient de la deuxième réponse est que cela ne fonctionne pas; il fait également pivoter la présentation vc lors du renvoi de la vc présentée. 

Cette solution permet la rotation dans tous les vc où vous avez mis canRotate () {} et ne fait pas pivoter le vc présentateur.

Swift 3:
Dans AppDelegate.Swift:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
        if (rootViewController.responds(to: Selector(("canRotate")))) {
            // Unlock landscape view orientations for this view controller if it is not currently being dismissed
            if !rootViewController.isBeingDismissed{
                return .allButUpsideDown
            }
        }
    }

    // Only allow portrait (standard behaviour)
    return .portrait
}

private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
    if (rootViewController == nil) {
        return nil
    }
    if (rootViewController.isKind(of: UITabBarController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
    } else if (rootViewController.isKind(of: UINavigationController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
    } else if (rootViewController.presentedViewController != nil) {
        return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
    }
    return rootViewController
}

Dans chaque contrôleur de vue où la rotation devrait être autorisée:

func canRotate(){}
1
kuhr

Dans le contrôleur de vue racine, essayez d'ajouter:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

Travaillé pour moi.

1
Joshua C. Lerner

Swift 3.0 OR ci-dessus, Il suffit de vérifier la propriété "isBeingDismissed" du contrôleur de vue présenté . Vous trouverez ci-dessous un exemple de code. Celui-ci fera pivoter le contrôleur de la vue de présentation en mode portrait immédiatement après que le contrôleur de vue présenté ait été congédié.

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController)
{
  if rootViewController.canRotateVC == true
  {
    if baseVC.isBeingDismissed == false
    {
      return .allButUpsideDown
    }
  }
}

  return .portrait}

vous pouvez obtenir topController par le code ci-dessous:

  private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController?{
if (rootViewController == nil) { return nil }if (rootViewController.isKind(of: (UITabBarController).self))
{
  return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
}
else if (rootViewController.isKind(of:(UINavigationController).self))
{
  return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
}
else if (rootViewController.presentedViewController != nil)
{
  return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController }
0
Hiren Panchal