Mis à jour pour Swift 5
preferredLayoutAttributesFittingAttributes
renommé preferredLayoutAttributesFitting
et utiliser le dimensionnement automatique
Mis à jour pour Swift 4
systemLayoutSizeFittingSize
renommé en systemLayoutSizeFitting
Mis à jour pour iOS 9
Après avoir vu ma solution GitHub casser sous iOS 9, j'ai finalement eu le temps d'examiner le problème de manière approfondie. J'ai maintenant mis à jour le référentiel pour inclure plusieurs exemples de configurations différentes pour les cellules à dimensionnement automatique. Ma conclusion est que les cellules à dimensionnement automatique sont excellentes en théorie mais en désordre dans la pratique. Un mot de prudence lors de l'utilisation de cellules à dimensionnement automatique.
TL; DR
Découvrez mon projet GitHub
Les cellules à dimensionnement automatique ne sont prises en charge qu'avec la disposition de flux, assurez-vous donc que c'est ce que vous utilisez.
Il y a deux choses que vous devez configurer pour que les cellules à dimensionnement automatique fonctionnent.
1. Ensemble estimatedItemSize
surUICollectionViewFlowLayout
La disposition du flux deviendra de nature dynamique une fois que vous aurez défini la estimatedItemSize
propriété.
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
2. Ajoutez un support pour le dimensionnement de votre sous-classe de cellules
Cela vient en 2 saveurs; Disposition automatique ou remplacement personnalisé de preferredLayoutAttributesFittingAttributes
.
Créer et configurer des cellules avec la disposition automatique
Je n'entrerai pas dans les détails à ce sujet car il y a un article SO brillant sur la configuration des contraintes pour une cellule. Méfiez-vous simplement que Xcode 6 a cassé un tas de choses avec iOS 7 donc, si vous prenez en charge iOS 7, vous devrez faire des choses comme s'assurer que le masque de redimensionnement automatique est défini sur contentView de la cellule et que les limites de contentView sont définies comme limites de la cellule lorsque la cellule est chargée (ie awakeFromNib
).
Ce que vous devez savoir, c'est que votre cellule doit être plus sérieusement contrainte qu'une cellule de vue Table. Par exemple, si vous voulez que votre largeur soit dynamique, votre cellule a besoin d'une contrainte de hauteur. De même, si vous voulez que la hauteur soit dynamique, vous aurez besoin d'une contrainte de largeur pour votre cellule.
Implémentez preferredLayoutAttributesFittingAttributes
dans votre cellule personnalisée
Lorsque cette fonction est appelée, votre vue a déjà été configurée avec du contenu (c'est-à-dire qu'elle cellForItem
a été appelée). En supposant que vos contraintes ont été correctement définies, vous pouvez avoir une implémentation comme celle-ci:
//forces the system to do one layout pass
var isHeightCalculated: Bool = false
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//Exhibit A - We need to cache our calculation to prevent a crash.
if !isHeightCalculated {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.width = CGFloat(ceilf(Float(size.width)))
layoutAttributes.frame = newFrame
isHeightCalculated = true
}
return layoutAttributes
}
REMARQUE Sur iOS 9, le comportement a changé un peu, ce qui pourrait entraîner des plantages sur votre implémentation si vous ne faites pas attention (voir plus ici ). Lorsque vous implémentez, preferredLayoutAttributesFittingAttributes
vous devez vous assurer que vous ne modifiez le cadre de vos attributs de disposition qu'une seule fois. Si vous ne le faites pas, la mise en page appellera votre implémentation indéfiniment et finira par planter. Une solution consiste à mettre en cache la taille calculée dans votre cellule et à l'invalider chaque fois que vous réutilisez la cellule ou modifiez son contenu comme je l'ai fait avec la isHeightCalculated
propriété.
Découvrez votre mise en page
À ce stade, vous devriez avoir des cellules dynamiques «fonctionnelles» dans votre collectionView. Je n'ai pas encore trouvé la solution prête à l'emploi suffisante lors de mes tests alors n'hésitez pas à commenter si vous en avez. Il se sent toujours comme UITableView
gagne la bataille pour le dimensionnement dynamique à mon humble avis.
Avertissements
N'oubliez pas que si vous utilisez des cellules prototypes pour calculer la taille estimée de l'élément, cela se cassera si votre XIB utilise des classes de taille . La raison en est que lorsque vous chargez votre cellule à partir d'un XIB, sa classe de taille sera configurée avec Undefined
. Cela ne sera rompu que sur iOS 8 et versions ultérieures, car sur iOS 7, la classe de taille sera chargée en fonction de l'appareil (iPad = Regular-Any, iPhone = Compact-Any). Vous pouvez soit définir l'estimationItemSize sans charger le XIB, soit charger la cellule à partir du XIB, l'ajouter à la collectionView (cela définira le traitCollection), effectuer la mise en page, puis la supprimer de la vue d'ensemble. Alternativement, vous pouvez également faire en sorte que votre cellule remplace le traitCollection
getter et retourne les traits appropriés. C'est à vous.
Faites-moi savoir si j'ai raté quelque chose, j'espère avoir aidé et bonne chance le codage