UICollectionView — collezioni e FlowLayout in iOS spiegati

Autore: IT Sectr Pubblicato: 2026-02-23 Tempo di lettura: 9 min

UICollectionView è un potente componente UIKit per iOS che gestisce la visualizzazione di collezioni di oggetti sotto forma di griglie, elenchi e layout personalizzati. A differenza di UITableView, UICollectionView non è limitato a una singola colonna: supporta il posizionamento arbitrario degli elementi tramite UICollectionViewLayout. Spieghiamo l'essenza di UICollectionView, come funzionano FlowLayout e CompositionalLayout e come creare celle personalizzate in Swift. In IT Sectr, usiamo UICollectionView per gallerie, cataloghi e bacheche. Per il confronto con le tabelle, leggi l'articolo su UITableView.

Punti chiave

  • UICollectionView — un componente UIKit per visualizzare collezioni in griglie, elenchi e layout arbitrari.
  • UICollectionViewFlowLayout — il layout standard con supporto per direzione, dimensioni delle celle e spaziature.
  • UICollectionViewCompositionalLayout — un layout moderno (iOS 13+) per sezioni complesse con blocchi, caroselli e gruppi.
  • UICollectionViewDiffableDataSource — un DataSource type-safe con calcolo automatico delle modifiche (iOS 13+).
  • UICollectionViewCell — una cella di base con backgroundView, selectedBackgroundView e contentView incorporati.

Cos'è UICollectionView in iOS?

UICollectionView è una classe del framework UIKit introdotta in iOS 6 (2012). Visualizza una collezione ordinata di celle (UICollectionViewCell) in un layout flessibile gestito da un oggetto UICollectionViewLayout. UICollectionView risolve lo stesso problema di UITableView (elenchi) ma con posizionamento arbitrario degli elementi: griglie, caroselli, mosaici, cascate.

Architettura UICollectionView è costruita sul pattern MVC: i dati nel DataSource, il layout in UICollectionViewLayout, il comportamento in UICollectionViewDelegate. Questa separazione consente di sostituire i layout senza modificare il codice dei dati. Secondo Apple (WWDC 2025), il 72% delle app iOS della top 100 dell'App Store utilizza UICollectionView per visualizzare contenuti. CollectionView supporta layout multi-colonna da iOS 6 e da iOS 13 ha ricevuto CompositionalLayout per sezioni complesse.

Ciclo di vita della cella

UICollectionView utilizza un pool di celle riutilizzabili (reuse queue), simile a UITableView. Il metodo dequeueReusableCell(withReuseIdentifier:for:) restituisce una cella dal pool o ne crea una nuova se il pool è vuoto. A differenza di UITableView, UICollectionViewCell ha un contentView incorporato in cui aggiungere tutte le subview — non aggiungerle direttamente alla cella, poiché contentView gestisce l'animazione corretta di selezione e modifica.

FlowLayout vs CompositionalLayout: confronto

UICollectionViewFlowLayout — il layout standard che funziona da iOS 6. Dispone gli elementi in righe (flow) con la possibilità di configurare la dimensione della cella, la direzione di scorrimento, le spaziature minime e le sezioni. UICollectionViewCompositionalLayout — un layout moderno (iOS 13+) che descrive il layout attraverso una combinazione di blocchi: gruppo → sezione → layout, dove ogni gruppo può essere orizzontale, verticale o personalizzato.

ParametroUICollectionViewFlowLayoutUICollectionViewCompositionalLayout
Versione minimaiOS 6iOS 13
Layout complessiSolo griglia o elenco sempliceSezioni con layout diversi, gruppi, caroselli
AdattabilitàTramite dimensione del delegatoNSCollectionLayoutDimension.fractionalWidth/Height
PrestazioniRenderizza tutti gli elementi visibiliCreazione pigra delle sezioni
Supporto iPadRichiede adattamento manualeGruppi adattivi tramite fractionalWidth
Complessità di implementazioneBassa (5–10 righe)Media (15–30 righe)
swift
// UICollectionView di base con 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
    }
}

Raccomandazione Apple (WWDC 2025): usa CompositionalLayout per i nuovi progetti. Offre più capacità per layout adattivi, funziona meglio con UIKit e SwiftUI tramite UICollectionView.Representable e supporta intestazioni di sezione con dimensione automatica. Mantieni FlowLayout per schermi semplici con una griglia di celle identiche e versione minima iOS 12 e inferiore.

UICollectionViewCell e UICollectionViewDelegate

UICollectionViewCell — la classe base per le celle di UICollectionView. Ogni cella contiene contentView (contenitore principale), backgroundView (sfondo predefinito), selectedBackgroundView (sfondo selezionato). Configura l'aspetto della cella all'interno di contentView — non aggiungere mai subview direttamente a UICollectionViewCell.

swift
// Cella personalizzata con configurazione
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)

        // Vincoli di 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 fornisce metodi per gestire la selezione, l'evidenziazione, i menu contestuali e il riordinamento. A differenza di UITableView, UICollectionViewDelegate consente di controllare non solo i tap sugli elementi ma anche la pressione lunga (menu contestuale tramite UIContextMenuInteraction). Per gestire i tap, implementa collectionView(_:didSelectItemAt:) — viene chiamato al completamento dell'animazione di selezione.

UICollectionViewDiffableDataSource: DataSource moderno

UICollectionViewDiffableDataSource — una sostituzione type-safe per UICollectionViewDataSource introdotta in iOS 13. Invece di gestire manualmente le celle tramite cellForItemAt, DiffableDataSource utilizza NSDiffableDataSourceSnapshot — un'istantanea dello stato dei dati che calcola automaticamente la differenza tra lo stato vecchio e quello nuovo e anima le modifiche.

swift
// DiffableDataSource con sezioni
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)
    }

    // Aggiornamento con animazione automatica
    func updateProducts(_ products: [Product]) {
        var snapshot = dataSource.snapshot()
        snapshot.deleteItems(snapshot.itemIdentifiers)
        snapshot.appendItems(products)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}

Vantaggi di DiffableDataSource: (1) animazione automatica — insert, delete, reload avvengono con animazione predefinita; (2) sicurezza dei tipi — sezioni ed elementi sono tipizzati, errori di compilazione invece di crash runtime; (3) Snapshot — l'istantanea dello stato può essere salvata, annullata, confrontata; (4) prestazioni — DiffableDataSource utilizza l'algoritmo di Hellier per calcolare il set minimo di modifiche. Apple (WWDC 2024) raccomanda DiffableDataSource per tutti i nuovi UICollectionView e di mantenere il vecchio DataSource solo per iOS 12 e versioni precedenti.

Creazione di un layout personalizzato con UICollectionViewLayout

UICollectionViewLayout — una classe astratta che controlla completamente il posizionamento degli elementi della collezione. Se FlowLayout e CompositionalLayout non sono adatti (ad esempio, layout circolare, spirale, diagramma), crea una sottoclasse di UICollectionViewLayout e sovrascrivi i metodi di preparazione del layout.

swift
// Layout circolare personalizzato
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]
    }
}

Prestazioni: un UICollectionViewLayout personalizzato deve memorizzare nella cache gli attributi in prepare() e restituirli in O(1) in layoutAttributesForItem(at:). Per collezioni con 1000+ elementi, usa aggiornamenti incrementali della cache tramite shouldInvalidateLayout(forBoundsChange:) — questo evita di ricalcolare l'intero layout durante lo scorrimento. Apple (WWDC 2023) raccomanda CompositionalLayout invece dei layout personalizzati: copre il 95% degli scenari senza dover scrivere un layout da zero.

UICollectionView vs UITableView: quando scegliere cosa

UITableView e UICollectionView sono i due componenti principali di UIKit per visualizzare elenchi. UITableView è più semplice e progettato per elenchi a colonna singola. UICollectionView è più flessibile e supporta qualsiasi layout. La scelta tra loro dipende dalla struttura visiva dei dati e dalla personalizzazione richiesta.

ParametroUITableViewUICollectionView
LayoutSolo elenco verticaleElenco, griglia, cascata, carosello, personalizzato
ComplessitàBassa (DataSource semplice)Media (Layout + DataSource + Delegate)
Cella predefinita4 stili (basic, subtitle, value1, value2)Solo vuota (personalizzata tramite contentView)
Modalità modificaIntegrata (delete, move, insert)Richiede implementazione manuale
Header/FooterIntegrati (viewForHeaderInSection)Tramite supplementary views
PrestazioniAlte per elenchiAlte per qualsiasi layout
iOS 6+Disponibile da iOS 2Disponibile da iOS 6

Regola pratica: usa UITableView se lo schermo è un semplice elenco di righe (impostazioni, contatti, menu). Usa UICollectionView se lo schermo richiede una griglia, scorrimento orizzontale, carosello, diverse dimensioni delle celle o raggruppamenti complessi. Da iOS 14, UITableView ha anche ottenuto il supporto di CompositionalLayout tramite UICollectionLayoutListConfiguration, consentendo di combinare i vantaggi di entrambi i componenti.

Domande frequenti

Come creare UICollectionView con scorrimento orizzontale?

Imposta scrollDirection = .horizontal in UICollectionViewFlowLayout. Per CompositionalLayout, usa NSCollectionLayoutSize con fractionalWidth per la larghezza adattiva del gruppo. Lo scorrimento orizzontale è adatto per caroselli, gallerie e categorie. Per lo scorrimento paginato, imposta collectionView.isPagingEnabled = true o usa UICollectionViewFlowLayout con itemSize = bounds.width.

Perché UICollectionView non visualizza le celle?

Verifica: (1) la cella è registrata tramite register(_:forCellWithReuseIdentifier:), (2) DataSource restituisce un conteggio elementi > 0, (3) la cella viene dequeue con il corretto reuseIdentifier, (4) itemSize non è zero (per FlowLayout). Un errore tipico è itemSize = CGSize.zero, che rende le celle con altezza zero. Imposta itemSize esplicitamente o implementa il delegato collectionView(_:layout:sizeForItemAt:).

Come aggiungere spaziatura tra le celle di UICollectionView?

Per FlowLayout: layout.minimumInteritemSpacing (tra elementi in una riga) e layout.minimumLineSpacing (tra righe). Per CompositionalLayout: NSCollectionLayoutGroup.interItemSpacing e contentInsets sul gruppo/sezione. sectionInset imposta i margini esterni della sezione. Usa sectionInsetReference = .fromContentInset per la corretta gestione della Safe Area.

Come aggiornare UICollectionView senza ricaricare?

Usa performBatchUpdates per animazioni di gruppo: collectionView.performBatchUpdates { insertItems, deleteItems, reloadItems }. Per aggiornamenti sicuri e animati, usa UICollectionViewDiffableDataSource: chiama dataSource.apply(snapshot, animatingDifferences: true) — tutte le modifiche verranno calcolate e applicate automaticamente senza insert/delete manuali.

UICollectionView vs CollectionView in SwiftUI?

In SwiftUI, gli equivalenti di UICollectionView sono LazyVGrid e LazyHGrid (iOS 14+). SwiftUI Grid è più semplice da scrivere (sintassi dichiarativa) ma inferiore a UICollectionView in prestazioni per 500+ elementi e personalizzazione dei layout. Per collezioni complesse, usa UICollectionView tramite UIViewRepresentable. Nei progetti IT Sectr, scegliamo UICollectionView per cataloghi e gallerie e SwiftUI Grid per schermi semplici.

Riepilogo

  • UICollectionView — un componente UIKit flessibile per griglie, elenchi, caroselli e layout personalizzati (iOS 6+).
  • FlowLayout è adatto per griglie semplici; CompositionalLayout (iOS 13+) per sezioni complesse con layout diversi.
  • UICollectionViewCell usa contentView per tutte le subview — non aggiungerle direttamente alla cella.
  • UICollectionViewDiffableDataSource — un DataSource moderno type-safe con animazione automatica delle modifiche.
  • UICollectionViewLayout personalizzato consente di creare layout arbitrari (cerchio, spirale, diagramma).
  • Il 72% delle app iOS della top 100 dell'App Store utilizza UICollectionView per visualizzare contenuti.
  • Per elenchi semplici, usa UITableView; per tutto il resto, usa UICollectionView.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche