Dans une verticale UICollectionView
,
Est-il possible d'avoir des cellules pleine largeur , mais autoriser le contrôle de la hauteur dynamique par mise en page automatique ?
Cela me semble peut-être la "question la plus importante dans iOS sans vraiment bonne réponse."
Important:
Notez que dans 99% des cas, pour obtenir des cellules pleine largeur + une hauteur dynamique de mise en page automatique, utilisez simplement une vue de tableau. C'est si facile.
Alors, quel est un exemple où vous avez besoin d'une vue de collection?
Les vues de collection sont incroyablement plus puissantes que les vues de table.
Un exemple simple où vous réellement devez utiliser une vue de la collecte, pour obtenir des cellules en pleine largeur + hauteur de dynamique autolayout:
Si vous animez entre deux mises en page dans une vue de collection. Par exemple, entre une disposition à 1 et 2 colonnes, lorsque l'appareil pivote.
C'est un idiome courant et normal dans iOS. Malheureusement, cela ne peut être réalisé qu'en résolvant le problème posé dans ce contrôle qualité. : - /
la source
SpringDamping
etinitialSpringVelocity
) dans le tableau Cell ..... jetez un œil à cette liste gonflable en utilisant tableView ,,,, pastebin.com/pFRQhkrX vous pouvez animer leTableViewCell
tableau dans lawillDisplayCell:(UITableViewCell *)cell
méthode delgate @Fattie vous pouvez accepter la réponse qui a résolu votre problème pour aider les autres qui recherchent le même problèmeRéponses:
1. Solution pour iOS 13+
Avec Swift 5.1 et iOS 13, vous pouvez utiliser des objets de mise en page compositionnelle pour résoudre votre problème.
L'exemple de code complet suivant montre comment afficher la multiligne à l'
UILabel
intérieur de la pleine largeurUICollectionViewCell
:CollectionViewController.swift
HeaderView.swift
CustomCell.swift
Affichage attendu:
2. Solution pour iOS 11+
Avec Swift 5.1 et iOS 11, vous pouvez sous
UICollectionViewFlowLayout
- classer et définir saestimatedItemSize
propriété surUICollectionViewFlowLayout.automaticSize
(cela indique au système que vous souhaitez gérer le redimensionnement automatiqueUICollectionViewCell
). Vous devrez ensuite remplacerlayoutAttributesForElements(in:)
etlayoutAttributesForItem(at:)
pour définir la largeur des cellules. Enfin, vous devrez remplacer lapreferredLayoutAttributesFitting(_:)
méthode de votre cellule et calculer sa hauteur.Le code complet suivant montre comment afficher une multiligne à l'
UILabel
intérieur de la pleine largeurUIcollectionViewCell
(contrainte parUICollectionView
la zone de sécurité de etUICollectionViewFlowLayout
les inserts de):CollectionViewController.swift
CustomFlowLayout.swift
HeaderView.swift
CustomCell.swift
Voici quelques implémentations alternatives pour
preferredLayoutAttributesFitting(_:)
:Affichage attendu:
la source
Problème
Vous recherchez une hauteur automatique et souhaitez également avoir une largeur totale, il n'est pas possible d'obtenir les deux en utilisant
UICollectionViewFlowLayoutAutomaticSize
.Vous voulez faire en utilisant
UICollectionView
donc ci-dessous est la solution pour vous.Solution
1. Si vous n'avez que
UILabel
dansCollectionViewCell
que défini lenumberOfLines=0
et qui a calculé la hauteur attendue deUIlable
, passez les trois paramètres2. Si votre
CollectionViewCell
contient uniquementUIImageView
et s'il est censé être dynamique en hauteur, vous devez obtenir la hauteur deUIImage
(vousUIImageView
devez avoir desAspectRatio
contraintes)3. S'il contient les deux, calculez leur hauteur et ajoutez-les ensemble.
1. Ajouter un
UICollectionViewDelegateFlowLayout
délégué dans votre viewController2. Implémentez la méthode déléguée
J'espère que cela vous aidera.
la source
return CGSize(width: view.frame.width/2, height: expectedHeight)
gardez également le remplissage en compte plutôt que de renvoyer la largeur, sinon deux cellules ne rentreraient pas dans une seule ligne.Il existe plusieurs façons de résoudre ce problème.
Une façon est de donner à la disposition de flux de vue de collection une taille estimée et de calculer la taille de cellule.
Remarque: comme mentionné dans les commentaires ci-dessous, à partir d'iOS 10, vous n'avez plus besoin de fournir une taille estimée pour déclencher l'appel à une cellule
func preferredLayoutAttributesFitting(_ layoutAttributes:)
. Auparavant (iOS 9) vous obligeait à fournir une taille estimée si vous vouliez interroger une cellule prefferedLayoutAttributes.(en supposant que vous utilisez des storyboards et que la vue de la collection soit connectée via IB)
Pour des cellules simples, cela suffira généralement. Si la taille est toujours incorrecte, dans la cellule de vue de collection, vous pouvez remplacerfunc preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes
, ce qui vous donnera un contrôle plus fin sur la taille de la cellule. Remarque: vous devrez toujours donner à la disposition de flux une taille estimée .Remplacez ensuite
func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes
pour renvoyer la taille correcte.Vous pouvez également utiliser une cellule de dimensionnement pour calculer la taille de la cellule dans le
UICollectionViewDelegateFlowLayout
.Bien qu'il ne s'agisse pas d'exemples parfaits pour la production, ils devraient vous aider à démarrer dans la bonne direction. Je ne peux pas dire que ce soit la meilleure pratique, mais cela fonctionne pour moi, même avec des cellules assez complexes contenant plusieurs étiquettes, qui peuvent ou non envelopper plusieurs lignes.
la source
preferredLayoutAttributesFitting
. J'ai ensuite ajouté une contrainte de ma part dans ladite fonction, se liant à la dimension fixe de sharedItemSize, FWIW, voir ma réponse ci-dessous.J'ai trouvé une solution assez simple à ce problème: à l'intérieur de ma CollectionViewCell, j'ai un UIView () qui n'est en fait qu'un arrière-plan. Pour obtenir la pleine largeur, je viens de définir les ancres suivantes
La "magie" se produit dans la première ligne. J'ai défini dynamiquement widthAnchor sur la largeur de l'écran. Il est également important de soustraire les encarts de votre CollectionView. Sinon, la cellule n'apparaîtra pas. Si vous ne voulez pas avoir une telle vue d'arrière-plan, rendez-la simplement invisible.
Le FlowLayout utilise les paramètres suivants
Le résultat est une cellule pleine largeur avec une hauteur dynamique.
la source
TRAVAIL!!! Testé sur IOS: 12.1 Swift 4.1
J'ai une solution très simple qui fonctionne simplement sans rupture de contrainte.
Ma ViewControllerClass
Classe CustomCell:
Ingrédient principal est la systemLayoutSizeFitting fonction Customcell. Et nous devons également définir la largeur de la vue à l'intérieur de Cell avec des contraintes.
la source
Vous devez ajouter une contrainte de largeur à CollectionViewCell
la source
Ensemble
estimatedItemSize
de votre disposition de flux:Définissez une contrainte de largeur dans la cellule et définissez-la pour qu'elle soit égale à la largeur de superview:
Exemple complet
Testé sur iOS 11.
la source
Personnellement, j'ai trouvé le meilleur moyen d'avoir un UICollectionView où AutoLayout détermine la taille tandis que chaque cellule peut avoir une taille différente est d'implémenter la fonction UICollectionViewDelegateFlowLayout sizeForItemAtIndexPath tout en utilisant une cellule réelle pour mesurer la taille.
J'en ai parlé dans l'un de mes articles de blog
Espérons que celui-ci vous aidera à réaliser ce que vous voulez. Je ne suis pas sûr à 100% mais je crois que contrairement à UITableView où vous pouvez en fait avoir une hauteur de cellules entièrement automatique en utilisant AutoLayout en conjonction avec
UICollectionView n'a pas une telle façon de laisser AutoLayout déterminer la taille car UICollectionViewCell ne remplit pas nécessairement toute la largeur de l'écran.
Mais voici une question pour vous : si vous avez besoin de cellules de pleine largeur d'écran, pourquoi vous embêtez-vous même à utiliser UICollectionView sur un bon vieux UITableView qui est livré avec les cellules de dimensionnement automatique?
la source
D'après mon commentaire sur la réponse d'Eric, ma solution est très similaire à la sienne, mais j'ai dû ajouter une contrainte dans favoriteSizeFor ... afin de contraindre à la dimension fixe.
Cette question a un certain nombre de doublons, j'y ai répondu en détail ici et fourni un exemple d'application fonctionnel ici.
la source
Je ne sais pas si cela se qualifie comme une "très bonne réponse", mais c'est ce que j'utilise pour y parvenir. Ma disposition de flux est horizontale et j'essaie d'ajuster la largeur avec la disposition automatique, donc c'est similaire à votre situation.
Ensuite, dans le contrôleur de vue où la contrainte de mise en page automatique est modifiée, je déclenche une NSNotification.
Dans ma sous-classe UICollectionView, j'écoute cette notification:
et invalider la mise en page:
Cela provoque
sizeForItemAt
le nouvel appel en utilisant la nouvelle taille de la vue de collection. Dans votre cas, il devrait pouvoir se mettre à jour compte tenu des nouvelles contraintes disponibles dans la mise en page.la source
Sur votre
viewDidLayoutSubviews
, définissez laestimatedItemSize
sur pleine largeur (la disposition fait référence à l'objet UICollectionViewFlowLayout):Sur votre cellule, assurez-vous que vos contraintes touchent à la fois le haut et le bas de la cellule (le code suivant utilise la cartographie pour simplifier la définition des contraintes mais vous pouvez le faire avec NSLayoutConstraint ou IB si vous le souhaitez):
Voila, vos cellules vont maintenant croître automatiquement en hauteur!
la source
Aucune des solutions ne fonctionnait pour moi car j'ai besoin d'une largeur dynamique pour s'adapter à la largeur des iPhones.
la source
Depuis iOS 10, nous avons une nouvelle API sur la disposition des flux pour ce faire.
Tout ce que vous devez faire est de définir votre
flowLayout.estimatedItemSize
à une nouvelle constante,UICollectionViewFlowLayoutAutomaticSize
.La source
la source
La mise en page automatique peut être utilisée pour le dimensionnement automatique des cellules dans CollectionView en 2 étapes faciles:
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
collectionView(:cellForItemAt:)
pour limiter la largeur de contentView à la largeur de collectionView.Voilà, vous obtiendrez le résultat souhaité. Reportez-vous aux éléments essentiels suivants pour le code complet:
Référence / Crédits:
Capture d'écran:
la source
Vous devez hériter de la classe UICollectionViewDelegateFlowLayout sur votre collectionViewController. Ajoutez ensuite la fonction:
En utilisant cela, vous avez la taille de largeur de la largeur de l'écran.
Et vous avez maintenant un collectionViewController avec des lignes en tant que tableViewController.
Si vous souhaitez que la taille de la hauteur de chaque cellule soit dynamique, vous devriez peut-être créer des cellules personnalisées pour chaque cellule dont vous avez besoin.
la source