UICollectionView — egy hatékony UIKit komponens iOS-hez, amely objektumgyűjtemények megjelenítését kezeli rácsok, listák és egyéni elrendezések formájában. A UITableView-től eltérően az UICollectionView nem korlátozódik egy oszlopra: támogatja az elemek tetszőleges elhelyezését az UICollectionViewLayout segítségével. Elmagyarázzuk az UICollectionView lényegét, hogyan működik a FlowLayout és a CompositionalLayout, és hogyan hozhatók létre egyéni cellák Swift-ben. Az IT Sectr-ben UICollectionView-t használunk galériákhoz, katalógusokhoz és hirdetőtáblákhoz. A táblázatokkal való összehasonlításhoz olvassa el a UITableView-ról szóló cikket.
Főbb pontok
UICollectionView — egy osztály az UIKit keretrendszerből, amelyet iOS 6-ban (2012) vezettek be. Rendezett cellagyűjteményt (UICollectionViewCell) jelenít meg egy rugalmas elrendezésben, amelyet egy UICollectionViewLayout objektum kezel. Az UICollectionView ugyanazt a feladatot oldja meg, mint a UITableView (listák), de az elemek tetszőleges elhelyezésével: rácsok, körhinták, mozaikok, kaszkádok.
Architektúra Az UICollectionView az MVC mintára épül: adatok — a DataSource-ben, elrendezés — az UICollectionViewLayout-ban, viselkedés — az UICollectionViewDelegate-ben. Ez a szétválasztás lehetővé teszi az elrendezések cseréjét az adatkód módosítása nélkül. Az Apple szerint (WWDC 2025) az App Store top 100-as listáján lévő iOS-alkalmazások 72%-a használ UICollectionView-t a tartalom megjelenítésére. A CollectionView iOS 6 óta támogatja a többoszlopos elrendezéseket, és iOS 13-tól megkapta a CompositionalLayout-ot összetett szakaszokhoz.
Az UICollectionView újrafelhasználható cellák készletét használja (reuse queue), hasonlóan a UITableView-hez. A dequeueReusableCell(withReuseIdentifier:for:) metódus visszaad egy cellát a készletből, vagy újat hoz létre, ha a készlet üres. A UITableView-től eltérően az UICollectionViewCell rendelkezik egy beépített contentView-vel, amelyhez az összes subview-t hozzá kell adni — ne adja hozzá őket közvetlenül a cellához, mert a contentView felelős a kijelölés és szerkesztés helyes animációjáért.
UICollectionViewFlowLayout — szabványos elrendezés, amely iOS 6 óta működik. Sorokba rendezi az elemeket (flow) a cellaméret, görgetési irány, minimális távolságok és szakaszok beállításának lehetőségével. UICollectionViewCompositionalLayout — modern elrendezés (iOS 13+), amely az elrendezést blokkok kombinációjával írja le: csoport → szakasz → elrendezés, ahol minden csoport lehet vízszintes, függőleges vagy egyéni.
| Paraméter | UICollectionViewFlowLayout | UICollectionViewCompositionalLayout |
|---|---|---|
| Minimális verzió | iOS 6 | iOS 13 |
| Összetett elrendezések | Csak egyszerű rács vagy lista | Különböző elrendezésű szakaszok, csoportok, körhinták |
| Adaptivitás | A delegált méretén keresztül | NSCollectionLayoutDimension.fractionalWidth/Height |
| Teljesítmény | Az összes látható elemet rendereli | Lusta szakaszlétrehozás |
| iPad támogatás | Kézi adaptációt igényel | Adaptív csoportok fractionalWidth segítségével |
| Írási komplexitás | Alacsony (5–10 sor) | Közepes (15–30 sor) |
// Alap UICollectionView FlowLayout-tal
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 ajánlása (WWDC 2025): új projektekhez használja a CompositionalLayout-ot. Több lehetőséget biztosít az adaptív elrendezésekhez, jobban működik az UIKit és SwiftUI elemekkel az UICollectionView.Representable segítségével, és támogatja az automatikus méretű szakaszfejléceket. Hagyja a FlowLayout-ot egyszerű, azonos cellákból álló rácsos képernyőkhöz és iOS 12-es vagy alacsonyabb minimális verzióhoz.
UICollectionViewCell — az UICollectionView celláinak alaposztálya. Minden cella tartalmaz egy contentView-t (fő tároló), backgroundView-t (alapértelmezett háttér), selectedBackgroundView-t (háttér kijelöléskor). Állítsa be a cella megjelenését a contentView-n belül — soha ne adjon hozzá subview-okat közvetlenül az UICollectionViewCell-hez.
// Egyéni cella konfigurációval
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 constraints
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 módszereket biztosít a kijelölés, kiemelés, helyi menük és átrendezés kezeléséhez. A UITableView-től eltérően az UICollectionViewDelegate nem csak az elemre kattintást, hanem a hosszú lenyomást is vezérelheti (helyi menü az UIContextMenuInteraction segítségével). A kattintás kezeléséhez implementálja a collectionView(_:didSelectItemAt:) metódust — ez a kijelölési animáció befejezésekor hívódik meg.
UICollectionViewDiffableDataSource — az UICollectionViewDataSource típusbiztos helyettesítője, amelyet iOS 13-ban vezettek be. A cellák manuális kezelése helyett a cellForItemAt segítségével a DiffableDataSource az NSDiffableDataSourceSnapshot-t használja — az adatállapot pillanatképét, amely automatikusan kiszámítja a régi és új állapot közötti különbséget és animálja a változásokat.
// DiffableDataSource szakaszokkal
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)
}
// Frissítés automatikus animációval
func updateProducts(_ products: [Product]) {
var snapshot = dataSource.snapshot()
snapshot.deleteItems(snapshot.itemIdentifiers)
snapshot.appendItems(products)
dataSource.apply(snapshot, animatingDifferences: true)
}
}
A DiffableDataSource előnyei: (1) automatikus animáció — az insert, delete, reload alapértelmezett animációval történik; (2) típusbiztonság — a szakaszok és elemek tipizáltak, fordítási hibák a runtime hibák helyett; (3) Snapshot — az állapot pillanatképét el lehet menteni, visszavonni, összehasonlítani; (4) teljesítmény — a DiffableDataSource a Hellir-algoritmust használja a minimális változtatáskészlet kiszámításához. Az Apple (WWDC 2024) a DiffableDataSource-t ajánlja minden új UICollectionView-hoz, a régi DataSource-t csak iOS 12 és régebbi verziókhoz hagyja meg.
UICollectionViewLayout — absztrakt osztály, amely teljes mértékben vezérli a gyűjtemény elemeinek elhelyezését. Ha a FlowLayout és a CompositionalLayout nem megfelelő (például kör alakú elrendezés, spirál, diagram), hozzon létre egy alosztályt az UICollectionViewLayout-ból, és írja felül az elrendezés előkészítésének metódusait.
// Egyéni kör alakú elrendezés
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]
}
}
Teljesítmény: az egyéni UICollectionViewLayout-nak gyorsítótáraznia kell az attribútumokat a prepare() metódusban, és O(1) időben vissza kell adnia azokat a layoutAttributesForItem(at:) metódusban. 1000+ elemű gyűjteményekhez használjon inkrementális gyorsítótár-frissítést a shouldInvalidateLayout(forBoundsChange:) segítségével — ez lehetővé teszi, hogy ne számítsa újra a teljes elrendezést görgetés közben. Az Apple (WWDC 2023) a CompositionalLayout-ot ajánlja az egyéni elrendezések helyett: az esetek 95%-át lefedi anélkül, hogy elrendezést kellene írnia a nulláról.
UITableView és UICollectionView — a két fő UIKit komponens listák megjelenítéséhez. A UITableView egyszerűbb, és egyoszlopos listákhoz készült. Az UICollectionView rugalmasabb, és bármilyen elrendezést támogat. A köztük való választás az adatok vizuális szerkezetétől és a szükséges testreszabástól függ.
| Paraméter | UITableView | UICollectionView |
|---|---|---|
| Elrendezés | Csak függőleges lista | Lista, rács, kaszkád, körhinta, egyéni |
| Komplexitás | Alacsony (egyszerű DataSource) | Közepes (Layout + DataSource + Delegate) |
| Alapértelmezett cella | 4 stílus (basic, subtitle, value1, value2) | Csak üres (egyéni a contentView segítségével) |
| Szerkesztési mód | Beépített (delete, move, insert) | Kézi implementációt igényel |
| Header/Footer | Beépített (viewForHeaderInSection) | Kiegészítő nézetek segítségével |
| Teljesítmény | Magas listákhoz | Magas bármilyen elrendezéshez |
| iOS 6+ | iOS 2-től elérhető | iOS 6-tól elérhető |
Gyakorlati szabály: használja a UITableView-t, ha a képernyő egyszerű sorból álló lista (beállítások, névjegyek, menü). Használja az UICollectionView-t, ha a képernyő rácsot, vízszintes görgetést, körhintát, különböző cellaméreteket vagy összetett csoportosítást igényel. iOS 14-től a UITableView is megkapta a CompositionalLayout támogatását az UICollectionLayoutListConfiguration segítségével, ami lehetővé teszi mindkét komponens előnyeinek kombinálását.
Gyakran ismételt kérdések
Állítsa be a scrollDirection = .horizontal értéket az UICollectionViewFlowLayout-ban. A CompositionalLayout-hoz használja a NSCollectionLayoutSize elemet fractionalWidth-vel a csoport adaptív szélességéhez. A vízszintes görgetés jó körhintákhoz, galériákhoz és kategóriákhoz. Lapozáshoz állítsa be a collectionView.isPagingEnabled = true értéket, vagy használja az UICollectionViewFlowLayout-ot itemSize = bounds.width értékkel.
Ellenőrizze: (1) a cella regisztrálva van-e a register(_:forCellWithReuseIdentifier:) segítségével, (2) a DataSource visszaadja-e az elemek számát > 0, (3) a cella a megfelelő reuseIdentifier-rel lett dequeue-olva, (4) az itemSize nem nulla (FlowLayout esetén). Tipikus hiba — itemSize = CGSize.zero, amelynél a cellák nulla magasságúak. Állítsa be az itemSize-ot explicit módon, vagy implementálja a collectionView(_:layout:sizeForItemAt:) delegáltat.
FlowLayout esetén: layout.minimumInteritemSpacing (elemek között egy sorban) és layout.minimumLineSpacing (sorok között). CompositionalLayout esetén: NSCollectionLayoutGroup.interItemSpacing és contentInsets a csoporton/szakaszon. A sectionInset a szakasz külső távolságait állítja be. Használja a sectionInsetReference = .fromContentInset értéket a Safe Area helyes figyelembevételéhez.
Használja a performBatchUpdates metódust csoportos animációkhoz: collectionView.performBatchUpdates { insertItems, deleteItems, reloadItems }. Biztonságos és animált frissítéshez használja az UICollectionViewDiffableDataSource-t: hívja meg a dataSource.apply(snapshot, animatingDifferences: true) metódust — az összes változás automatikusan kiszámításra és alkalmazásra kerül manuális insert/delete nélkül.
A SwiftUI-ben az UICollectionView megfelelője a LazyVGrid és a LazyHGrid (iOS 14+). A SwiftUI Grid egyszerűbb írásban (deklaratív szintaxis), de gyengébb teljesítményű az UICollectionView-nál 500+ elem és elrendezés-testreszabás esetén. Összetett gyűjteményekhez használja az UICollectionView-t az UIViewRepresentable segítségével. Az IT Sectr projektjeiben az UICollectionView-t választjuk katalógusokhoz és galériákhoz, a SwiftUI Grid-et egyszerű képernyőkhöz.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is