UICollectionView ist eine leistungsstarke UIKit-Komponente für iOS, die die Anzeige von Objektsammlungen in Form von Rastern, Listen und benutzerdefinierten Layouts verwaltet. Im Gegensatz zu UITableView ist UICollectionView nicht auf eine einzelne Spalte beschränkt: Es unterstützt die beliebige Positionierung von Elementen über UICollectionViewLayout. Wir erklären das Wesen von UICollectionView, wie FlowLayout und CompositionalLayout funktionieren und wie man benutzerdefinierte Zellen in Swift erstellt. Bei IT Sectr verwenden wir UICollectionView für Galerien, Kataloge und Anzeigentafeln. Für den Vergleich mit Tabellen lesen Sie den Artikel über UITableView.
Wichtige Punkte
UICollectionView ist eine Klasse des UIKit-Frameworks, die in iOS 6 (2012) eingeführt wurde. Sie zeigt eine geordnete Sammlung von Zellen (UICollectionViewCell) in einem flexiblen Layout an, das von einem UICollectionViewLayout-Objekt verwaltet wird. UICollectionView löst das gleiche Problem wie UITableView (Listen), jedoch mit beliebiger Elementpositionierung: Raster, Karussells, Mosaike, Kaskaden.
Architektur UICollectionView basiert auf dem MVC-Muster: Daten in der DataSource, Layout in UICollectionViewLayout, Verhalten in UICollectionViewDelegate. Diese Trennung ermöglicht den Austausch von Layouts ohne Änderung des Daten-Codes. Laut Apple (WWDC 2025) verwenden 72% der iOS-Apps aus den Top 100 des App Store UICollectionView zur Inhaltsanzeige. CollectionView unterstützt mehrspaltige Layouts seit iOS 6 und erhielt mit iOS 13 CompositionalLayout für komplexe Abschnitte.
UICollectionView verwendet einen Pool wiederverwendbarer Zellen (reuse queue), ähnlich wie UITableView. Die Methode dequeueReusableCell(withReuseIdentifier:for:) gibt eine Zelle aus dem Pool zurück oder erstellt eine neue, wenn der Pool leer ist. Im Gegensatz zu UITableView hat UICollectionViewCell einen integrierten contentView, dem alle Subviews hinzugefügt werden sollten — fügen Sie sie nicht direkt zur Zelle hinzu, da contentView für die korrekte Auswahl- und Bearbeitungsanimation verantwortlich ist.
UICollectionViewFlowLayout — das Standard-Layout, das seit iOS 6 funktioniert. Es ordnet Elemente in Zeilen (flow) an und ermöglicht die Konfiguration von Zellgröße, Scrollrichtung, Mindestabständen und Abschnitten. UICollectionViewCompositionalLayout — ein modernes Layout (iOS 13+), das das Layout durch eine Kombination von Blöcken beschreibt: Gruppe → Abschnitt → Layout, wobei jede Gruppe horizontal, vertikal oder benutzerdefiniert sein kann.
| Parameter | UICollectionViewFlowLayout | UICollectionViewCompositionalLayout |
|---|---|---|
| Mindestversion | iOS 6 | iOS 13 |
| Komplexe Layouts | Nur einfaches Raster oder Liste | Abschnitte mit verschiedenen Layouts, Gruppen, Karussells |
| Anpassungsfähigkeit | Über Delegatgröße | NSCollectionLayoutDimension.fractionalWidth/Height |
| Leistung | Rendert alle sichtbaren Elemente | Faule Abschnittserstellung |
| iPad-Unterstützung | Erfordert manuelle Anpassung | Adaptive Gruppen über fractionalWidth |
| Implementierungskomplexität | Niedrig (5–10 Zeilen) | Mittel (15–30 Zeilen) |
// Basis-UICollectionView mit 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
}
}
Apple-Empfehlung (WWDC 2025): Verwenden Sie CompositionalLayout für neue Projekte. Es bietet mehr Möglichkeiten für adaptive Layouts, arbeitet besser mit UIKit und SwiftUI über UICollectionView.Representable und unterstützt Abschnittsüberschriften mit automatischer Größe. Behalten Sie FlowLayout für einfache Bildschirme mit einem Raster identischer Zellen und iOS 12 und niedriger als Mindestversion.
UICollectionViewCell — die Basisklasse für UICollectionView-Zellen. Jede Zelle enthält contentView (Hauptcontainer), backgroundView (Standard-Hintergrund) und selectedBackgroundView (Hintergrund bei Auswahl). Konfigurieren Sie das Erscheinungsbild der Zelle innerhalb von contentView — fügen Sie niemals Subviews direkt zu UICollectionViewCell hinzu.
// Benutzerdefinierte Zelle mit Konfiguration
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)
// Auto-Layout-Einschränkungen
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 stellt Methoden zur Behandlung von Auswahl, Hervorhebung, Kontextmenüs und Neuanordnung bereit. Im Gegensatz zu UITableView ermöglicht UICollectionViewDelegate nicht nur das Verarbeiten von Element-Tipps, sondern auch von langem Druck (Kontextmenü über UIContextMenuInteraction). Für die Behandlung von Tipps implementieren Sie collectionView(_:didSelectItemAt:) — es wird aufgerufen, wenn die Auswahlanimation abgeschlossen ist.
UICollectionViewDiffableDataSource — ein typsicherer Ersatz für UICollectionViewDataSource, eingeführt in iOS 13. Anstatt Zellen manuell über cellForItemAt zu verwalten, verwendet DiffableDataSource NSDiffableDataSourceSnapshot — einen Snapshot des Datenzustands, der automatisch die Differenz zwischen altem und neuem Zustand berechnet und Änderungen animiert.
// DiffableDataSource mit Abschnitten
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)
}
// Aktualisierung mit automatischer Animation
func updateProducts(_ products: [Product]) {
var snapshot = dataSource.snapshot()
snapshot.deleteItems(snapshot.itemIdentifiers)
snapshot.appendItems(products)
dataSource.apply(snapshot, animatingDifferences: true)
}
}
Vorteile von DiffableDataSource: (1) automatische Animation — insert, delete, reload erfolgen mit Standard-Animation; (2) Typsicherheit — Abschnitte und Elemente sind typisiert, Compiler-Fehler statt Laufzeit-Abstürze; (3) Snapshot — der Zustands-Snapshot kann gespeichert, rückgängig gemacht und verglichen werden; (4) Leistung — DiffableDataSource verwendet den Hellier-Algorithmus zur Berechnung der minimalen Änderungsmenge. Apple (WWDC 2024) empfiehlt DiffableDataSource für alle neuen UICollectionViews und die alte DataSource nur für iOS 12 und älter.
UICollectionViewLayout — eine abstrakte Klasse, die die Positionierung der Sammlungselemente vollständig steuert. Wenn FlowLayout und CompositionalLayout nicht geeignet sind (z. B. kreisförmiges Layout, Spirale, Diagramm), erstellen Sie eine Unterklasse von UICollectionViewLayout und überschreiben Sie die Layout-Vorbereitungsmethoden.
// Benutzerdefiniertes kreisförmiges Layout
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]
}
}
Leistung: Ein benutzerdefiniertes UICollectionViewLayout sollte Attribute in prepare() zwischenspeichern und in O(1) in layoutAttributesForItem(at:) zurückgeben. Für Sammlungen mit 1000+ Elementen verwenden Sie inkrementelle Cache-Updates über shouldInvalidateLayout(forBoundsChange:) — dies vermeidet eine Neuberechnung des gesamten Layouts beim Scrollen. Apple (WWDC 2023) empfiehlt CompositionalLayout anstelle benutzerdefinierter Layouts: es deckt 95% der Szenarien ab, ohne ein Layout von Grund auf neu schreiben zu müssen.
UITableView und UICollectionView sind die beiden wichtigsten UIKit-Komponenten zur Anzeige von Listen. UITableView ist einfacher und für einspaltige Listen konzipiert. UICollectionView ist flexibler und unterstützt jedes Layout. Die Wahl zwischen ihnen hängt von der visuellen Datenstruktur und der erforderlichen Anpassung ab.
| Parameter | UITableView | UICollectionView |
|---|---|---|
| Layout | Nur vertikale Liste | Liste, Raster, Kaskade, Karussell, benutzerdefiniert |
| Komplexität | Niedrig (einfache DataSource) | Mittel (Layout + DataSource + Delegate) |
| Standard-Zelle | 4 Stile (basic, subtitle, value1, value2) | Nur leer (benutzerdefiniert über contentView) |
| Bearbeitungsmodus | Integriert (delete, move, insert) | Erfordert manuelle Implementierung |
| Header/Footer | Integriert (viewForHeaderInSection) | Über supplementary views |
| Leistung | Hoch für Listen | Hoch für jedes Layout |
| iOS 6+ | Verfügbar seit iOS 2 | Verfügbar seit iOS 6 |
Praktische Regel: Verwenden Sie UITableView, wenn der Bildschirm eine einfache Liste von Zeilen ist (Einstellungen, Kontakte, Menü). Verwenden Sie UICollectionView, wenn der Bildschirm ein Raster, horizontales Scrollen, Karussell, unterschiedliche Zellgrößen oder komplexe Gruppierung erfordert. Seit iOS 14 unterstützt UITableView ebenfalls CompositionalLayout über UICollectionLayoutListConfiguration, was die Kombination der Vorteile beider Komponenten ermöglicht.
Häufig gestellte Fragen
Setzen Sie scrollDirection = .horizontal im UICollectionViewFlowLayout. Für CompositionalLayout verwenden Sie NSCollectionLayoutSize mit fractionalWidth für adaptive Gruppenbreite. Horizontales Scrollen eignet sich gut für Karussells, Galerien und Kategorien. Für seitenweises Scrollen setzen Sie collectionView.isPagingEnabled = true oder verwenden Sie UICollectionViewFlowLayout mit itemSize = bounds.width.
Überprüfen Sie: (1) die Zelle ist über register(_:forCellWithReuseIdentifier:) registriert, (2) DataSource gibt eine Elementanzahl > 0 zurück, (3) die Zelle wird mit der richtigen reuseIdentifier aus der Warteschlange genommen, (4) itemSize ist nicht Null (für FlowLayout). Ein typischer Fehler ist itemSize = CGSize.zero, bei dem Zellen eine Höhe von Null haben. Setzen Sie itemSize explizit oder implementieren Sie den Delegaten collectionView(_:layout:sizeForItemAt:).
Für FlowLayout: layout.minimumInteritemSpacing (zwischen Elementen in einer Zeile) und layout.minimumLineSpacing (zwischen Zeilen). Für CompositionalLayout: NSCollectionLayoutGroup.interItemSpacing und contentInsets auf der Gruppe/dem Abschnitt. sectionInset legt die äußeren Ränder des Abschnitts fest. Verwenden Sie sectionInsetReference = .fromContentInset für korrekte Safe-Area-Behandlung.
Verwenden Sie performBatchUpdates für Gruppen-Animationen: collectionView.performBatchUpdates { insertItems, deleteItems, reloadItems }. Für sichere und animierte Aktualisierungen verwenden Sie UICollectionViewDiffableDataSource: rufen Sie dataSource.apply(snapshot, animatingDifferences: true) auf — alle Änderungen werden automatisch berechnet und angewendet, ohne manuelles insert/delete.
In SwiftUI sind die Entsprechungen von UICollectionView LazyVGrid und LazyHGrid (iOS 14+). SwiftUI Grid ist einfacher zu schreiben (deklarative Syntax), aber in der Leistung für 500+ Elemente und Layout-Anpassung UICollectionView unterlegen. Verwenden Sie für komplexe Sammlungen UICollectionView über UIViewRepresentable. In IT Sectr-Projekten wählen wir UICollectionView für Kataloge und Galerien und SwiftUI Grid für einfache Bildschirme.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch