web-dev-qa-db-fra.com

UICollectionView en paysage sur iPhone X

Lorsque l'iPhone X est utilisé en mode paysage, vous êtes censé vérifier que les safeAreaInsets permettent de créer des gouttières suffisamment grandes à gauche et à droite. UITableView a la nouvelle propriété insetsContentViewsToSafeArea (valeur par défaut) pour conserver automatiquement le contenu des cellules dans la zone sécurisée.

Je suis surpris qu'UICollectionView ne semble rien avoir de semblable. Je m'attendrais à ce que pour une vue de collection à défilement vertical, les côtés gauche et droit soient insérés dans la zone de sécurité en paysage (et inversement, une vue de collection à défilement horizontal serait insérée si nécessaire en mode portrait).

Le moyen le plus simple d’assurer ce comportement semble être d’ajouter au contrôleur de vue de collection:

- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    UIEdgeInsets contentInset = self.collectionView.contentInset;
    contentInset.left = self.view.safeAreaInsets.left;
    contentInset.right = self.view.safeAreaInsets.right;
    self.collectionView.contentInset = contentInset;
}

... en supposant que contentInset.left/right est normalement nul.

(REMARQUE: oui, pour UICollectionViewController, il doit être self.view.safeAreaInsets; au moment de l'appel, le changement de safeAreaInsets n'a curieusement pas encore été propagé à self.collectionView)

Est-ce que je manque quelque chose? Ce modèle standard est assez simple, mais il est effectivement nécessaire maintenant pour chaque vue de collection qui touche un bord d’écran. Il semble vraiment étrange qu'Apple n'ait pas fourni quelque chose pour l'activer par défaut.

34
Wes Campaigne

Alors que Nathan a raison sur la polyvalence d’UICollectionView avec différentes mises en page, je me suis surtout préoccupé du cas "par défaut" dans lequel on utilise UICollectionViewFlowLayout.

Il s'avère que iOS 11 a ajouté une propriété sectionInsetReference à UICollectionViewFlowLayout. La documentation officielle manque actuellement de description, mais les en-têtes le décrivent comme

La limite de référence à laquelle la section insère sera définie par rapport à. La valeur par défaut est .fromContentInset.

NOTE: Le contenu inséré sera toujours respecté au minimum. Par exemple, si sectionInsetReference est égal à .fromSafeArea, mais si l'insertion de contenu ajusté est supérieure à la combinaison des zones de sécurité et des insertions de section, le contenu de la section sera alors aligné sur l'encart de contenu.

Les valeurs possibles sont

@available(iOS 11.0, *)
public enum UICollectionViewFlowLayoutSectionInsetReference : Int {
    case fromContentInset
    case fromSafeArea
    case fromLayoutMargins
}

et le régler sur .fromSafeArea produit les résultats souhaités, c’est-à-dire lorsque vous êtes initialement en mode portrait:

 initial portrait layout

puis, lors de la rotation vers le paysage, les cellules sont insérées de sorte qu'elles se trouvent entièrement dans la zone de sécurité:

 iPhone X landscape collection view layout

... CEPENDANT, il y a actuellement un bogue, et lorsque vous revenez à portrait après que la vue soit dans paysage, elle continue à agir comme si les safeAreaInsets gauche/droite étaient définis sur les valeurs de paysage:

 portrait layout following rotation from landscape

J'ai déposé un radar ( rdar: // 34491993 ) concernant ce problème.

38
Wes Campaigne

Avoir le même problème. Cela a fonctionné pour moi:

override func viewDidLoad() {
    if #available(iOS 11.0, *) {
        collectionView?.contentInsetAdjustmentBehavior = .always
    }
}

La documentation pour le cas .always enum dit: 

Toujours inclure les encarts de la zone de sécurité dans l'ajustement du contenu.

Cette solution fonctionne correctement également dans le cas où le téléphone est pivoté.

47
petrsyn

Merci à ci-dessus pour l'aide. Pour ma sous-classe UICollectionViewController, j'ai ajouté ce qui suit à viewDidLoad () (Swift 3):

if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
    if #available(iOS 11.0, *) {
        flowLayout.sectionInsetReference = .fromSafeArea
    }
}
7
anorskdev

Gardez à l'esprit que les solutions ci-dessus ne résolvent pas le cas où vos vues de cellule de collection (et les sous-vues limitées aux bords avant ou arrière de sa cellule) ont toute la largeur des limites de la vue de collection et ne sont pas définies pour obéir Zone sécurisée Guides de mise en page

Remarque: La réponse de @petrsyn crée un en-tête inséré par les côtés, ce que la plupart des gens ne voudraient peut-être pas. La réponse de @Wes Campaigne ne fonctionne pas correctement pour les cellules de pleine largeur, dans lesquelles une sous-vue est attachée à la première ou à la fin. bords de la cellule. 

Il est impératif, en particulier pour ceux issus de projets plus anciens, de définir vos fichiers Xib et Storyboard sur Utilisez les guides de mise en forme des zones sûres , puis utilisez la mise en page automatique pour appliquer des contraintes respectives aux zones sécurisées ou faire une codage similaire.

1
iAmcR

UICollectionView est conçu pour être flexible pour une grande variété de dispositions. Les mises en page les plus courantes sont les grilles avec plusieurs lignes et colonnes, mais il est possible de créer des mises en page non-grille avec UICollectionView.

UITableView, en revanche, est conçu pour les cellules de pleine largeur.

Par conséquent, il est logique que UITableView dispose d'une prise en charge intégrée permettant de traiter les incrustations pour zones sûres, étant donné que les dispositions de vue de tableau en seront toujours affectées. Étant donné que UICollectionView utilise des dispositions personnalisées, il est judicieux de résoudre ces problèmes sur chaque base d'implémentation au lieu d'essayer de fournir une solution unique.

0
nathangitter