web-dev-qa-db-fra.com

UICollectionView, cellules pleine largeur, autorisent la hauteur dynamique autolayout?

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".

51
Fattie

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 UICollectionViewCells). 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:

 enter image description here

23
Imanou Petit

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.

22
Dhiru

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.

15
Eric Murphey

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.

 enter image description here

10
inf1783

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
  }
}
3
Mecid

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? 

3
xxtesaxx

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.

2
Mark Suman

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.

1
Chris Conover
  1. Définissez estimatedItemSize de votre structure de flux:

    collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
    
  2. 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.

1
Roman

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.

Source: http://asciiwwdc.com/2016/sessions/219

1
Arpit Dongre

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!

1
Raphael

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()
        }
    }
0
iOS Flow

TRAVAIL !!! Testé sur IOS: 12.1 Swift 4.1

J'ai une solution très simple qui fonctionne sans aucune contrainte.

enter image description here

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.

0
Abhishek Biswas