web-dev-qa-db-fra.com

Quelle est la "bonne" façon de gérer les changements d'orientation dans iOS 8?

Quelqu'un peut-il me dire s'il vous plaît quelle est la "bonne" ou la "meilleure" approche pour travailler avec les orientations d'interface portrait et paysage dans iOS 8? Il semble que toutes les fonctions que je souhaite utiliser à cet effet soient obsolètes dans iOS 8, et mes recherches n’ont abouti à aucune alternative claire et élégante. Suis-je vraiment censé regarder la largeur et la hauteur pour déterminer moi-même si nous sommes en mode portrait ou paysage?

Par exemple, dans mon contrôleur de vue, comment dois-je implémenter le pseudocode suivant?

if we are rotating from portrait to landscape then
  do portrait things
else if we are rotating from landscape to portrait then
  do landscape things
99
rmp251

Apple recommande d’utiliser les classes de taille comme mesure approximative de la quantité d’espace disponible sur l’écran, afin que votre interface utilisateur puisse changer de manière significative sa disposition et son apparence. Considérez qu'un iPad en portrait a les mêmes classes de taille que dans le paysage (largeur normale, hauteur normale). Cela signifie que votre interface utilisateur doit être plus ou moins similaire entre les deux orientations.

Cependant, le passage de portrait en paysage dans un iPad est suffisamment important pour que vous deviez peut-être effectuer quelques ajustements moins importants de l'interface utilisateur, même si les classes de taille n'ont pas changé. Puisque les méthodes liées à l'orientation de l'interface sur UIViewController sont obsolètes, Apple recommande désormais d'implémenter la nouvelle méthode suivante dans UIViewController en remplacement:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // Code here will execute before the rotation begins.
    // Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Place code here to perform animations during the rotation.
        // You can pass nil or leave this block empty if not necessary.

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Code here will execute after the rotation has finished.
        // Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]

    }];
}

Génial! Vous recevez maintenant des rappels juste avant le début et après la fin de la rotation. Mais qu'en est-il de savoir réellement si la rotation est au portrait ou au paysage?

Apple recommande de considérer la rotation comme un simple changement de taille de la vue parente. En d'autres termes, lors d'une rotation iPad de portrait en paysage, vous pouvez la considérer comme une vue de niveau racine modifiant simplement son bounds.size de {768, 1024} à {1024, 768}. Sachant cela, vous devez utiliser la méthode size passée dans la méthode viewWillTransitionToSize:withTransitionCoordinator: ci-dessus pour déterminer si vous effectuez une rotation en mode portrait ou paysage.

Si vous souhaitez un moyen encore plus transparent de migrer le code hérité vers le nouveau mode de fonctionnement iOS 8, envisagez d'utiliser cette catégorie simple sur UIView, qui peut être utilisé pour déterminer si une vue est "portrait". ou "paysage" en fonction de sa taille.

Récapituler:

  1. Vous devez utiliser des classes de taille pour déterminer quand afficher des interfaces utilisateur fondamentalement différentes (par exemple une interface utilisateur "semblable à un iPhone" par rapport à une interface utilisateur "similaire à un iPad").
  2. Si vous devez apporter de petits ajustements à votre interface utilisateur lorsque les classes de taille ne changent pas , mais que la taille de votre conteneur (vue parent) le fait, par exemple lorsqu'un iPad tourne, utilisez le callback viewWillTransitionToSize:withTransitionCoordinator: dans UIViewController.
  3. Chaque vue de votre application doit uniquement prendre des décisions de mise en page en fonction de l'espace qui lui a été attribué. Laisser la hiérarchie naturelle des vues cascader ces informations.
  4. De même, n'utilisez pas la variable statusBarOrientation, qui est essentiellement une propriété au niveau du périphérique, pour déterminer si vous souhaitez mettre en forme une vue pour "portrait" ou "paysage". L'orientation de la barre d'état ne doit être utilisée que par le code traitant d'éléments tels que UIWindow, qui résident en réalité au niveau racine de l'application.
253
smileyborg

Sur la base de la réponse très bien détaillée (et acceptée) de smileyborg, voici une adaptation utilisant Swift 3:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        self.collectionView.collectionViewLayout.invalidateLayout()
    })        
}

Et dans la UICollectionViewDelegateFlowLayout mise en œuvre,

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // retrieve the updated bounds
    let itemWidth = collectionView.bounds.width
    let itemHeight = collectionView.bounds.height
    // do whatever you need to do to adapt to the new size
}
16
CMont

J'utilise simplement Notification Center:

Ajouter une variable d'orientation (expliquera à la fin)

//Above viewdidload
var orientations:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation

Ajouter une notification lorsque la vue apparaît

override func viewDidAppear(animated: Bool) {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name: UIDeviceOrientationDidChangeNotification, object: nil)
}

Supprimer la notification lorsque la vue disparaît

override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil) 
}

Obtient l'orientation actuelle lorsque la notification est déclenchée

func orientationChanged (notification: NSNotification) {
    adjustViewsForOrientation(UIApplication.sharedApplication().statusBarOrientation)
}

Vérifie l'orientation (portrait/paysage) et gère les événements

func adjustViewsForOrientation(orientation: UIInterfaceOrientation) {
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown)
    {
        if(orientation != orientations) {
            println("Portrait")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
    else if (orientation == UIInterfaceOrientation.LandscapeLeft || orientation == UIInterfaceOrientation.LandscapeRight)
    {
       if(orientation != orientations) {
            println("Landscape")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
}

La raison pour laquelle j'ai ajouté une variable d'orientation est que, lors des tests sur un périphérique physique, la notification d'orientation est appelée à chaque déplacement mineur du périphérique, et pas uniquement lors de sa rotation. L'ajout des instructions var et if n'appelle le code que s'il a basculé dans l'orientation opposée.

11
inVINCEable

Du point de vue de l'interface utilisateur, l'utilisation des classes de taille est l'approche recommandée par Apple pour la gestion des interfaces dans différentes orientations, tailles et échelles.

Voir la section: Traits Décrivez la classe de taille et l'échelle d'une interface ici: https://developer.Apple.com/library/ios/releasenotes/General/ WhatsNewIniOS/Articles/iOS8.html

"iOS 8 ajoute de nouvelles fonctionnalités qui rendent la gestion de la taille et de l'orientation de l'écran beaucoup plus polyvalente."

Celui-ci est également un bon article: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

EDIT Lien mis à jour: https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (Crédit: Koen)

2
Aaron