Voici une question assez élémentaire sur le développement iOS actuel, à laquelle je n’ai jamais trouvé de réponse satisfaisante.
Dans une (disons) verticale UICollectionView
,
Est-il possible d'avoir cellules pleine largeur , mais, permettre à la hauteur dynamique d'être contrôlée par autolayout?
(Si vous débutez sur iOS, "hauteur dynamique", ce qui signifie que la cellule comporte quelques vues, par exemple, du texte (longueur quelconque) ou des images de tailles différentes, de sorte que chaque cellule présente une hauteur totalement différente.
Si c'est le cas, comment?
Cela me semble être peut-être la "question la plus importante sous iOS sans vraiment bonne réponse".
Avec Swift 4.2 et iOS 12, vous pouvez sous-classer UICollectionViewFlowLayout
et définir sa propriété estimatedItemSize
sur UICollectionViewFlowLayoutAutomaticSize
(cela indique au système que vous souhaitez gérer le redimensionnement automatique UICollectionViewCell
s). Vous devrez ensuite remplacer layoutAttributesForElements(in:)
et layoutAttributesForItem(at:)
afin de définir la largeur des cellules. Enfin, vous devrez redéfinir votre méthode de cellules preferredLayoutAttributesFitting(_:)
et calculer leur hauteur de raccord compressée.
Le code complet suivant montre comment afficher plusieurs lignes UILabel
à l'intérieur de la largeur UIcollectionViewCell
pleine largeur (contrainte par la zone de sécurité de UICollectionView
et les incrustations de UICollectionViewFlowLayout
):
CollectionViewController.Swift
import UIKit
class CollectionViewController: UICollectionViewController {
let items = [
"Lorem ipsum.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam."
]
let columnLayout = FlowLayout()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.alwaysBounceVertical = true
collectionView.collectionViewLayout = columnLayout
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.register(Cell.self, forCellWithReuseIdentifier: "Cell")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.label.text = items[indexPath.row]
return cell
}
}
FlowLayout.Swift
import UIKit
class FlowLayout: UICollectionViewFlowLayout {
override init() {
super.init()
self.minimumInteritemSpacing = 10
self.minimumLineSpacing = 10
self.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil }
guard let collectionView = collectionView else { return nil }
layoutAttributes.bounds.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right
return layoutAttributes
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let superLayoutAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
guard scrollDirection == .vertical else { return superLayoutAttributes }
let computedAttributes = superLayoutAttributes.compactMap { layoutAttribute in
return layoutAttribute.representedElementCategory == .cell ? layoutAttributesForItem(at: layoutAttribute.indexPath) : layoutAttribute
}
return computedAttributes
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
Cell.Swift
import UIKit
class Cell: UICollectionViewCell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
label.numberOfLines = 0
backgroundColor = .orange
contentView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
layoutIfNeeded()
let layoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
layoutAttributes.bounds.size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow)
return layoutAttributes
}
}
Voici quelques implémentations alternatives pour preferredLayoutAttributesFitting(_:)
:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
layoutIfNeeded()
label.preferredMaxLayoutWidth = label.bounds.size.width
layoutAttributes.bounds.size.height = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
label.preferredMaxLayoutWidth = layoutAttributes.size.width - contentView.layoutMargins.left - contentView.layoutMargins.left
layoutAttributes.bounds.size.height = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
Affichage attendu:
Problème
Vous recherchez une hauteur automatique et souhaitez aussi avoir une largeur complète, Il n’est pas possible d’utiliser les deux en utilisant UICollectionViewFlowLayoutAutomaticSize
. Pourquoi vous ne prenez pas UITableVIew
au lieu de UICollectionView
dans lequel vous pouvez simplement revenir heightForRow
comme UITableViewAutomaticDimension
il sera géré automatiquement. Quoi qu'il en soit, vous souhaitez utiliser UICollectionView
. La solution ci-dessous vous convient.
Solution
Étape I: : Calculer la hauteur attendue de la cellule
1. : Si vous avez uniquement UILabel
dans ColllectionViewCell
que de définir le numberOfLines=0
et qui a calculé la hauteur attendue de UIlable
, transmettez les trois paramètres.
func heightForLable(text:String, font:UIFont, width:CGFloat) -> CGFloat{
// pass string ,font , LableWidth
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
2. : si votre ColllectionViewCell
ne contient que UIImageView
et s'il est supposé être dynamique en hauteur, vous devez obtenir la hauteur de UIImage
(votre UIImageView
doit avoir des contraintes AspectRatio
)
// this will give you the height of your Image
let heightInPoints = image.size.height
let heightInPixels = heightInPoints * image.scale
3. s'il contient à la fois que calculé leur hauteur et les additionner.
ETAPE-II : Retourne la taille de
CollectionViewCell
1. Ajouter UICollectionViewDelegateFlowLayout
délégué dans votre viewController
2. Implémenter la méthode delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// This is Just for example , for the scenario Step-I -> 1
let yourWidthOfLable=self.view.size.width
let font = UIFont(name: "Helvetica", size: 20.0)
var expectedHeight = heightForLable(array[indePath.row], font: font, width:yourWidthOfLable )
return CGSize(width: view.frame.width, height: expectedHeight)
}
j'espère que cela vous aidera.
Vous pouvez résoudre ce problème de plusieurs manières.
Vous pouvez par exemple attribuer à la disposition du flux de vue de collection une taille estimée et calculer la taille de la cellule.
Remarque: Comme mentionné dans les commentaires ci-dessous, à partir d'iOS 10, vous n'avez plus besoin de fournir de taille estimée pour déclencher l'appel d'une cellule func preferredLayoutAttributesFitting(_ layoutAttributes:)
. Auparavant (iOS 9), vous deviez fournir une taille estimée pour interroger une cellule prefferedLayoutAttributes.
(en supposant que vous utilisez des storyboards et que la vue de collection soit connectée via IB)
override func viewDidLoad() {
super.viewDidLoad()
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.estimatedItemSize = CGSize(width: 375, height: 200) // your average cell size
}
Pour les cellules simples, cela suffit généralement. Si la taille est toujours incorrecte, vous pouvez remplacer la fonction func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes
dans la cellule de la vue Collection, ce qui vous donnera un contrôle plus fin du grain sur la taille de la cellule. Remarque: vous devrez toujours attribuer à la structure de flux une taille estimée .
Ensuite, remplacez func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes
pour retourner la taille correcte.
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityDefaultLow)
let autoLayoutFrame = CGRect(Origin: autoLayoutAttributes.frame.Origin, size: autoLayoutSize)
autoLayoutAttributes.frame = autoLayoutFrame
return autoLayoutAttributes
}
Vous pouvez également utiliser une cellule de dimensionnement pour calculer la taille de la cellule dans la variable UICollectionViewDelegateFlowLayout
.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width
let size = CGSize(width: width, height: 0)
// assuming your collection view cell is a nib
// you may also instantiate a instance of our cell from a storyboard
let sizingCell = UINib(nibName: "yourNibName", bundle: nil).instantiate(withOwner: nil, options: nil).first as! YourCollectionViewCell
sizingCell.autoresizingMask = [.flexibleWidth, .flexibleHeight]
sizingCell.frame.size = size
sizingCell.configure(with: object[indexPath.row]) // what ever method configures your cell
return sizingCell.contentView.systemLayoutSizeFitting(size, withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityDefaultLow)
}
Bien que ces exemples ne soient pas 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 être renvoyées à plusieurs lignes.
J'ai trouvé une solution assez simple à ce problème: À l'intérieur de ma CollectionViewCell, j'ai obtenu un UIView () qui n'est en réalité qu'un arrière-plan. Pour obtenir toute la largeur je viens de définir les ancres suivantes
bgView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.size.width - 30).isActive = true // 30 is my added up left and right Inset
bgView.topAnchor.constraint(equalTo: topAnchor).isActive = true
bgView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
bgView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
bgView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
La "magie" se passe en première ligne. J'ai réglé le widthAnchor dynamiquement à la largeur de l'écran. Il est également important de soustraire les incrustations de votre CollectionView. Sinon, la cellule ne se présentera pas. Si vous ne voulez pas avoir une telle vue en arrière-plan, rendez-la invisible.
FlowLayout utilise les paramètres suivants
layout.itemSize = UICollectionViewFlowLayoutAutomaticSize
layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
Le résultat est une cellule pleine largeur avec une hauteur dynamique.
Vous devez ajouter une contrainte de largeur à CollectionViewCell
class SelfSizingCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
}
}
Personnellement, j'ai trouvé le meilleur moyen d'avoir un UICollectionView où AutoLayout détermine la taille alors que chaque cellule peut avoir une taille différente est d'implémenter la fonction UICollectionViewDelegateFlowLayout sizeForItemAtIndexPath lors de l'utilisation d'une cellule réelle pour mesurer la taille.
J'en ai parlé dans l'un de mes billets de blog: https://janthielemann.de/ios-development/self-sizing-uicollectionviewcells-ios-10-Swift-3/
Espérons que celui-ci vous aidera à réaliser ce que vous voulez. Je ne suis pas sûr à 100%, mais je pense que contrairement à UITableView, vous pouvez obtenir une hauteur de cellules entièrement automatique en utilisant la déconnexion AutoLayout avec
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
UICollectionView ne dispose pas d'un tel moyen 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 en plein écran, pourquoi ne pas utiliser UICollectionView avec un bon vieil UITableView fourni avec les cellules de redimensionnement automatique?
Je ne sais pas si cela constitue une "très bonne réponse", mais c'est ce que j'utilise pour accomplir cela. Ma structure de flux est horizontale et j'essaie de faire en sorte que la largeur s'ajuste avec l'autolayout pour qu'elle ressemble à votre situation.
extension PhotoAlbumVC: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// My height is static, but it could use the screen size if you wanted
return CGSize(width: collectionView.frame.width - sectionInsets.left - sectionInsets.right, height: 60)
}
}
Ensuite, dans le contrôleur de vue où la contrainte d'autolayout est modifiée, je déclenche une notification NSNotification.
NotificationCenter.default.post(name: NSNotification.Name("constraintMoved"), object: self, userInfo: nil)
Dans ma sous-classe UICollectionView, j'écoute cette notification:
// viewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(handleConstraintNotification(notification:)), name: NSNotification.Name("constraintMoved"), object: nil)
et invalider la mise en page:
func handleConstraintNotification(notification: Notification) {
self.collectionView?.collectionViewLayout.invalidateLayout()
}
sizeForItemAt
est alors appelé à nouveau à l'aide de la nouvelle taille de la vue de collection. Dans votre cas, il devrait être capable de mettre à jour compte tenu des nouvelles contraintes disponibles dans la mise en page.
D'après mon commentaire sur la réponse d'Eric, ma solution est très similaire à la sienne, mais je devais ajouter une contrainte dans preferredSizeFor ... afin de limiter la dimension fixe.
override func systemLayoutSizeFitting(
_ targetSize: CGSize, withHorizontalFittingPriority
horizontalFittingPriority: UILayoutPriority,
verticalFittingPriority: UILayoutPriority) -> CGSize {
width.constant = targetSize.width
let size = contentView.systemLayoutSizeFitting(
CGSize(width: targetSize.width, height: 1),
withHorizontalFittingPriority: .required,
verticalFittingPriority: verticalFittingPriority)
print("\(#function) \(#line) \(targetSize) -> \(size)")
return size
}
Cette question a un certain nombre de doublons, j'y ai répondu en détail ici: https://stackoverflow.com/a/47424930/2171044 , et fourni un exemple d'application working ici.
Définissez estimatedItemSize
de votre structure de flux:
collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
Définissez une contrainte de largeur dans la cellule et réglez-la sur la largeur de superview:
class CollectionViewCell: UICollectionViewCell {
private var widthConstraint: NSLayoutConstraint?
...
override init(frame: CGRect) {
...
// Create width constraint to set it later.
widthConstraint = contentView.widthAnchor.constraint(equalToConstant: 0)
}
override func updateConstraints() {
// Set width constraint to superview's width.
widthConstraint?.constant = superview?.bounds.width ?? 0
widthConstraint?.isActive = true
super.updateConstraints()
}
...
}
Exemple complet: https://Gist.github.com/madyanov/246217ad2628ba6a870114131a27c55c
Testé sur iOS 11.
Pour iOS 10, nous avons une nouvelle API sur la disposition des flux pour le faire.
Tout ce que vous avez à faire est de définir votre flowLayout.estimatedItemSize
sur une nouvelle constante, UICollectionViewFlowLayoutAutomaticSize
.
Sur votre viewDidLayoutSubviews
, définissez la estimatedItemSize
sur toute la largeur (la présentation fait référence à l'objet UICollectionViewFlowLayout):
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.bounds.size.width, height: 120)
}
Sur votre cellule, assurez-vous que vos contraintes touchent le haut et le bas de la cellule (le code suivant utilise Cartographie pour simplifier la définition des contraintes, mais vous pouvez le faire avec NSLayoutConstraint ou IB si vous le souhaitez):
constrain(self, nameLabel, valueLabel) { view, name, value in
name.top == view.top + 10
name.left == view.left
name.bottom == view.bottom - 10
value.right == view.right
value.centerY == view.centerY
}
Voila, vos cellules vont maintenant s'ouvrir automatiquement en hauteur!
Aucune des solutions ne fonctionnait pour moi car j'avais besoin de la largeur dynamique pour m'adapter à la largeur de l'iPhone.
class CustomLayoutFlow: UICollectionViewFlowLayout {
override init() {
super.init()
minimumInteritemSpacing = 1 ; minimumLineSpacing = 1 ; scrollDirection = .horizontal
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
minimumInteritemSpacing = 1 ; minimumLineSpacing = 1 ; scrollDirection = .horizontal
}
override var itemSize: CGSize {
set { }
get {
let width = (self.collectionView?.frame.width)!
let height = (self.collectionView?.frame.height)!
return CGSize(width: width, height: height)
}
}
}
class TextCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var textView: UITextView!
override func prepareForReuse() {
super.prepareForReuse()
}
}
class IntroViewController: UIViewController, UITextViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UINavigationControllerDelegate {
@IBOutlet weak var collectionViewTopDistanceConstraint: NSLayoutConstraint!
@IBOutlet weak var collectionViewTopDistanceConstraint: NSLayoutConstraint!
@IBOutlet weak var collectionView: UICollectionView!
var collectionViewLayout: CustomLayoutFlow!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionViewLayout = CustomLayoutFlow()
self.collectionView.collectionViewLayout = self.collectionViewLayout
}
override func viewWillLayoutSubviews() {
self.collectionViewTopDistanceConstraint.constant = UIScreen.main.bounds.height > 736 ? 94 : 70
self.view.layoutIfNeeded()
}
}
TRAVAIL !!! Testé sur IOS: 12.1 Swift 4.1
J'ai une solution très simple qui fonctionne sans aucune contrainte.
My ViewControllerClass
class ViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
let cellId = "CustomCell"
var source = ["nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,","nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,","nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,"]
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.delegate = self
self.collectionView.dataSource = self
self.collectionView.register(UINib.init(nibName: cellId, bundle: nil), forCellWithReuseIdentifier: cellId)
if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.source.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as? CustomCell else { return UICollectionViewCell() }
cell.setData(data: source[indexPath.item])
return cell
}
}
classe CustomCell:
class CustomCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var widthConstraint: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
self.widthConstraint.constant = UIScreen.main.bounds.width
}
func setData(data: String) {
self.label.text = data
}
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
return contentView.systemLayoutSizeFitting(CGSize(width: self.bounds.size.width, height: 1))
}
}
L'ingrédient principal est la fonction systemLayoutSizeFitting dans Customcell. Nous devons également définir la largeur de la vue à l'intérieur de la cellule avec des contraintes.