UICollectionView — collections et FlowLayout dans iOS expliqués

Auteur : IT Sectr Publié le : 2026-02-23 Temps de lecture : 9 min

UICollectionView est un composant puissant d'UIKit pour iOS qui gère l'affichage de collections d'objets sous forme de grilles, listes et layouts personnalisés. Contrairement à UITableView, UICollectionView n'est pas limité à une seule colonne : il prend en charge le positionnement arbitraire des éléments via UICollectionViewLayout. Nous expliquons l'essence d'UICollectionView, comment fonctionnent FlowLayout et CompositionalLayout, et comment créer des cellules personnalisées en Swift. Chez IT Sectr, nous utilisons UICollectionView pour les galeries, catalogues et panneaux d'annonces. Pour une comparaison avec les tableaux, lisez l'article sur UITableView.

Points clés

  • UICollectionView — un composant UIKit pour afficher des collections en grilles, listes et layouts arbitraires.
  • UICollectionViewFlowLayout — le layout standard prenant en charge la direction, les tailles de cellule et les espacements.
  • UICollectionViewCompositionalLayout — un layout moderne (iOS 13+) pour les sections complexes avec blocs, carrousels et groupes.
  • UICollectionViewDiffableDataSource — une DataSource type-safe avec calcul automatique des changements (iOS 13+).
  • UICollectionViewCell — une cellule de base avec backgroundView, selectedBackgroundView et contentView intégrés.

Qu'est-ce que UICollectionView dans iOS ?

UICollectionView est une classe du framework UIKit introduite dans iOS 6 (2012). Elle affiche une collection ordonnée de cellules (UICollectionViewCell) dans un layout flexible géré par un objet UICollectionViewLayout. UICollectionView résout le même problème que UITableView (listes) mais avec un positionnement arbitraire des éléments : grilles, carrousels, mosaïques, cascades.

Architecture UICollectionView est construite sur le modèle MVC : les données dans la DataSource, le layout dans UICollectionViewLayout, le comportement dans UICollectionViewDelegate. Cette séparation permet de remplacer les layouts sans modifier le code des données. Selon Apple (WWDC 2025), 72% des applications iOS du top 100 de l'App Store utilisent UICollectionView pour afficher du contenu. CollectionView prend en charge les layouts multi-colonnes depuis iOS 6, et depuis iOS 13, il a reçu CompositionalLayout pour les sections complexes.

Cycle de vie d'une cellule

UICollectionView utilise un pool de cellules réutilisables (reuse queue), similaire à UITableView. La méthode dequeueReusableCell(withReuseIdentifier:for:) retourne une cellule du pool ou en crée une nouvelle si le pool est vide. Contrairement à UITableView, UICollectionViewCell dispose d'un contentView intégré dans lequel vous devez ajouter toutes les sous-vues — ne les ajoutez pas directement à la cellule, car contentView gère l'animation correcte de sélection et d'édition.

FlowLayout vs CompositionalLayout : comparaison

UICollectionViewFlowLayout — le layout standard qui fonctionne depuis iOS 6. Il dispose les éléments en lignes (flow) avec la possibilité de configurer la taille de cellule, la direction de défilement, les espacements minimaux et les sections. UICollectionViewCompositionalLayout — un layout moderne (iOS 13+) qui décrit le layout via une combinaison de blocs : groupe → section → layout, où chaque groupe peut être horizontal, vertical ou personnalisé.

ParamètreUICollectionViewFlowLayoutUICollectionViewCompositionalLayout
Version minimaleiOS 6iOS 13
Layouts complexesSeulement grille ou liste simpleSections avec différents layouts, groupes, carrousels
AdaptabilitéVia la taille du déléguéNSCollectionLayoutDimension.fractionalWidth/Height
PerformanceRend tous les éléments visiblesCréation paresseuse des sections
Support iPadNécessite une adaptation manuelleGroupes adaptatifs via fractionalWidth
Complexité d'implémentationFaible (5–10 lignes)Moyenne (15–30 lignes)
swift
// UICollectionView de base avec FlowLayout
class ViewController: UIViewController {

    private var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.minimumInteritemSpacing = 8
        layout.minimumLineSpacing = 12
        layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
        layout.itemSize = CGSize(width: view.frame.width - 32, height: 100)

        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "cell")
        collectionView.dataSource = self
        view.addSubview(collectionView)
    }
}

// DataSource
extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView,
                         numberOfItemsInSection section: Int) -> Int { 20 }

    func collectionView(_ collectionView: UICollectionView,
                         cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        as! CustomCell
        cell.configure(with: "Item \(indexPath.row)")
        return cell
    }
}

Recommandation d'Apple (WWDC 2025) : utilisez CompositionalLayout pour les nouveaux projets. Il offre plus de capacités pour les layouts adaptatifs, fonctionne mieux avec UIKit et SwiftUI via UICollectionView.Representable, et prend en charge les en-têtes de section avec taille automatique. Gardez FlowLayout pour les écrans simples avec une grille de cellules identiques et une version minimale iOS 12 et inférieure.

UICollectionViewCell et UICollectionViewDelegate

UICollectionViewCell — la classe de base pour les cellules d'UICollectionView. Chaque cellule contient contentView (conteneur principal), backgroundView (arrière-plan par défaut), selectedBackgroundView (arrière-plan sélectionné). Configurez l'apparence de la cellule à l'intérieur de contentView — n'ajoutez jamais de sous-vues directement à UICollectionViewCell.

swift
// Cellule personnalisée avec configuration
class ProductCell: UICollectionViewCell {

    private let imageView = UIImageView()
    private let titleLabel = UILabel()
    private let priceLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupViews() {
        contentView.addSubview(imageView)
        contentView.addSubview(titleLabel)
        contentView.addSubview(priceLabel)

        // Contraintes Auto Layout
        imageView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
            imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor),
            titleLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 8),
            titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8),
            titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8),
            priceLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4),
            priceLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8)
        ])
    }

    func configure(with product: Product) {
        imageView.image = UIImage(named: product.imageName)
        titleLabel.text = product.title
        priceLabel.text = product.price
    }
}

UICollectionViewDelegate fournit des méthodes pour gérer la sélection, le surlignage, les menus contextuels et le réordonnancement. Contrairement à UITableView, UICollectionViewDelegate permet de contrôler non seulement les tap sur les éléments mais aussi l'appui long (menu contextuel via UIContextMenuInteraction). Pour gérer les tap, implémentez collectionView(_:didSelectItemAt:) — il est appelé lorsque l'animation de sélection est terminée.

UICollectionViewDiffableDataSource : DataSource moderne

UICollectionViewDiffableDataSource — un remplacement type-safe d'UICollectionViewDataSource introduit dans iOS 13. Au lieu de gérer manuellement les cellules via cellForItemAt, DiffableDataSource utilise NSDiffableDataSourceSnapshot — un instantané de l'état des données qui calcule automatiquement la différence entre l'état ancien et le nouvel état et anime les changements.

swift
// DiffableDataSource avec sections
enum Section {
    case featured, recommended, categories
}

class ModernDataSource: UIViewController {

    private var dataSource: UICollectionViewDiffableDataSource<Section, Product>!

    override func viewDidLoad() {
        super.viewDidLoad()
        configureDataSource()
        applyInitialSnapshot()
    }

    private func configureDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<ProductCell, Product> { cell, _, product in
            cell.configure(with: product)
        }

        dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) {
            collectionView, indexPath, product in
            collectionView.dequeueConfiguredReusableCell(
                using: cellRegistration, for: indexPath, item: product
            )
        }
    }

    private func applyInitialSnapshot() {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Product>()
        snapshot.appendSections([.featured, .recommended, .categories])
        snapshot.appendItems(featuredProducts, toSection: .featured)
        snapshot.appendItems(recommendedProducts, toSection: .recommended)
        snapshot.appendItems(categories, toSection: .categories)
        dataSource.apply(snapshot, animatingDifferences: true)
    }

    // Mise à jour avec animation automatique
    func updateProducts(_ products: [Product]) {
        var snapshot = dataSource.snapshot()
        snapshot.deleteItems(snapshot.itemIdentifiers)
        snapshot.appendItems(products)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}

Avantages de DiffableDataSource : (1) animation automatique — insert, delete, reload se produisent avec une animation par défaut ; (2) sécurité de type — les sections et les éléments sont typés, erreurs de compilation au lieu de plantages runtime ; (3) Snapshot — l'instantané d'état peut être sauvegardé, annulé, comparé ; (4) performance — DiffableDataSource utilise l'algorithme de Hellier pour calculer l'ensemble minimal de changements. Apple (WWDC 2024) recommande DiffableDataSource pour tous les nouveaux UICollectionView, et de conserver l'ancienne DataSource uniquement pour iOS 12 et versions antérieures.

Création d'un layout personnalisé avec UICollectionViewLayout

UICollectionViewLayout — une classe abstraite qui contrôle entièrement le positionnement des éléments de la collection. Si FlowLayout et CompositionalLayout ne conviennent pas (par exemple, layout circulaire, spirale, diagramme), créez une sous-classe d'UICollectionViewLayout et remplacez les méthodes de préparation du layout.

swift
// Layout circulaire personnalisé
class CircularLayout: UICollectionViewLayout {

    private var attributesCache: [UICollectionViewLayoutAttributes] = []

    private let radius: CGFloat = 120

    override func prepare() {
        super.prepare()
        attributesCache.removeAll()

        guard let collectionView else { return }
        let count = collectionView.numberOfItems(inSection: 0)
        let center = CGPoint(x: collectionView.bounds.midX, y: collectionView.bounds.midY)

        for i in 0..<count {
            let indexPath = IndexPath(item: i, section: 0)
            let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
            let angle = (CGFloat(i) / CGFloat(count)) * 2 * .pi

            attributes.center = CGPoint(
                x: center.x + radius * cos(angle),
                y: center.y + radius * sin(angle)
            )
            attributes.size = CGSize(width: 60, height: 60)
            attributesCache.append(attributes)
        }
    }

    override var collectionViewContentSize: CGSize {
        collectionView?.bounds.size ?? .zero
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        attributesCache.filter { $0.frame.intersects(rect) }
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        attributesCache[indexPath.item]
    }
}

Performance : un UICollectionViewLayout personnalisé doit mettre en cache les attributs dans prepare() et les retourner en O(1) dans layoutAttributesForItem(at:). Pour les collections de 1000+ éléments, utilisez des mises à jour incrémentielles du cache via shouldInvalidateLayout(forBoundsChange:) — cela évite de recalculer l'ensemble du layout lors du défilement. Apple (WWDC 2023) recommande CompositionalLayout plutôt que les layouts personnalisés : il couvre 95% des scénarios sans avoir à écrire un layout à partir de zéro.

UICollectionView vs UITableView : quand choisir quoi

UITableView et UICollectionView sont les deux principaux composants UIKit pour afficher des listes. UITableView est plus simple et conçu pour les listes à une seule colonne. UICollectionView est plus flexible et prend en charge tout type de layout. Le choix entre eux dépend de la structure visuelle des données et de la personnalisation requise.

ParamètreUITableViewUICollectionView
LayoutListe verticale uniquementListe, grille, cascade, carrousel, personnalisé
ComplexitéFaible (DataSource simple)Moyenne (Layout + DataSource + Delegate)
Cellule par défaut4 styles (basic, subtitle, value1, value2)Vide uniquement (personnalisée via contentView)
Mode éditionIntégré (delete, move, insert)Nécessite une implémentation manuelle
Header/FooterIntégrés (viewForHeaderInSection)Via les supplementary views
PerformanceÉlevée pour les listesÉlevée pour tout layout
iOS 6+Disponible depuis iOS 2Disponible depuis iOS 6

Règle pratique : utilisez UITableView si l'écran est une simple liste de lignes (paramètres, contacts, menu). Utilisez UICollectionView si l'écran nécessite une grille, un défilement horizontal, un carrousel, différentes tailles de cellule ou un regroupement complexe. Depuis iOS 14, UITableView a également obtenu le support de CompositionalLayout via UICollectionLayoutListConfiguration, permettant de combiner les avantages des deux composants.

Foire aux questions

Comment faire un UICollectionView avec défilement horizontal ?

Définissez scrollDirection = .horizontal dans UICollectionViewFlowLayout. Pour CompositionalLayout, utilisez NSCollectionLayoutSize avec fractionalWidth pour la largeur adaptative du groupe. Le défilement horizontal est adapté aux carrousels, galeries et catégories. Pour le défilement paginé, définissez collectionView.isPagingEnabled = true ou utilisez UICollectionViewFlowLayout avec itemSize = bounds.width.

Pourquoi UICollectionView n'affiche-t-il pas les cellules ?

Vérifiez : (1) la cellule est enregistrée via register(_:forCellWithReuseIdentifier:), (2) la DataSource retourne un nombre d'éléments > 0, (3) la cellule est défilée avec le bon reuseIdentifier, (4) itemSize n'est pas nul (pour FlowLayout). Une erreur typique est itemSize = CGSize.zero, qui donne aux cellules une hauteur nulle. Définissez itemSize explicitement ou implémentez le délégué collectionView(_:layout:sizeForItemAt:).

Comment ajouter de l'espacement entre les cellules UICollectionView ?

Pour FlowLayout : layout.minimumInteritemSpacing (entre les éléments d'une ligne) et layout.minimumLineSpacing (entre les lignes). Pour CompositionalLayout : NSCollectionLayoutGroup.interItemSpacing et contentInsets sur le groupe/la section. sectionInset définit les marges externes de la section. Utilisez sectionInsetReference = .fromContentInset pour une gestion correcte de la Safe Area.

Comment mettre à jour UICollectionView sans rechargement ?

Utilisez performBatchUpdates pour les animations groupées : collectionView.performBatchUpdates { insertItems, deleteItems, reloadItems }. Pour des mises à jour sûres et animées, utilisez UICollectionViewDiffableDataSource : appelez dataSource.apply(snapshot, animatingDifferences: true) — tous les changements seront calculés et appliqués automatiquement sans insert/delete manuel.

UICollectionView vs CollectionView dans SwiftUI ?

Dans SwiftUI, les équivalents d'UICollectionView sont LazyVGrid et LazyHGrid (iOS 14+). SwiftUI Grid est plus simple à écrire (syntaxe déclarative) mais inférieur à UICollectionView en performance pour 500+ éléments et en personnalisation de layouts. Pour les collections complexes, utilisez UICollectionView via UIViewRepresentable. Dans les projets IT Sectr, nous choisissons UICollectionView pour les catalogues et galeries, et SwiftUI Grid pour les écrans simples.

Résumé

  • UICollectionView — un composant UIKit flexible pour les grilles, listes, carrousels et layouts personnalisés (iOS 6+).
  • FlowLayout convient pour les grilles simples ; CompositionalLayout (iOS 13+) pour les sections complexes avec différents layouts.
  • UICollectionViewCell utilise contentView pour toutes les sous-vues — ne les ajoutez pas directement à la cellule.
  • UICollectionViewDiffableDataSource — une DataSource moderne type-safe avec animation automatique des changements.
  • UICollectionViewLayout personnalisé permet de créer des layouts arbitraires (cercle, spirale, diagramme).
  • 72% des applications iOS du top 100 de l'App Store utilisent UICollectionView pour afficher du contenu.
  • Pour les listes simples, utilisez UITableView ; pour tout le reste, utilisez UICollectionView.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi