UICollectionView là control hiển thị dữ liệu theo lưới (grid), danh sách, hoặc layout tùy chỉnh mạnh mẽ hơn TableView. Cần conform UICollectionViewDataSource, UICollectionViewDelegate, và UICollectionViewDelegateFlowLayout cho size tùy chỉnh.
1. Tạo Collection View bằng code
func setupCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.backgroundColor = .systemGroupedBackground
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(collectionView)
}
2. DataSource (Bắt buộc)
func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = .systemRed
cell.layer.cornerRadius = 8
// Thêm label hiển thị index
if cell.contentView.subviews.isEmpty {
let label = UILabel(frame: cell.contentView.bounds)
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.textAlignment = .center
label.textColor = .white
label.font = .boldSystemFont(ofSize: 18)
label.tag = 999
cell.contentView.addSubview(label)
}
(cell.contentView.viewWithTag(999) as? UILabel)?.text = "\(indexPath.item)"
return cell
}
3. Delegate Flow Layout (Size động)
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
// Ví dụ: 2 cột, spacing 10
let width = (collectionView.bounds.width - 30) / 2
return CGSize(width: width, height: width) // Vuông
}
Kết quả

Nâng cao: Compositional Layout (iOS 13+)
Thay UICollectionViewFlowLayout bằng UICollectionViewCompositionalLayout cho layout phức tạp (nested groups, orthogonal scrolling, header/footer, badge...).
func createLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.5))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous // Hoặc .groupPaging, .none
return UICollectionViewCompositionalLayout(section: section)
}
// Sử dụng:
let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
Lưu ý
- Luôn dùng
dequeueReusableCell(withReuseIdentifier:for:)– không init cell mới mỗi lần. - Custom Cell: Tạo class kế thừa
UICollectionViewCell, register nib/class. - Supplementary Views (Header/Footer):
register(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "header"). - Diffable Data Source (iOS 13+):
UICollectionViewDiffableDataSource– cập nhật data an toàn, animate tự động.