UICollectionView — суштина, колекције и FlowLayout у iOS-у

Аутор: IT Sectr Објављено: 2026-02-23 Време читања: 9 мин

UICollectionView — моћна UIKit компонента за iOS која управља приказом колекција објеката у виду мрежа, листи и прилагођених макета. За разлику од UITableView-а, UICollectionView није ограничен на једну колону: подржава произвољан распоред елемената путем UICollectionViewLayout-а. Објашњавамо суштину UICollectionView-а, како раде FlowLayout и CompositionalLayout, и како креирати прилагођене ћелије у Swift-у. У IT Sectr-у користимо UICollectionView за галерије, каталоге и огласне табле. За поређење са табелама прочитајте чланак о UITableView-у.

Главне тачке

  • UICollectionView — UIKit компонента за приказ колекција у виду мрежа, листи и произвољних макета.
  • UICollectionViewFlowLayout — стандардни макет са подршком за правац, величине ћелија и интервале.
  • UICollectionViewCompositionalLayout — савремени макет (iOS 13+) за сложене секције са блоковима, каруселима и групама.
  • UICollectionViewDiffableDataSource — тип-безбедни DataSource са аутоматским израчунавањем промена (iOS 13+).
  • UICollectionViewCell — основна ћелија са уграђеним backgroundView, selectedBackgroundView и contentView.

Шта је UICollectionView у iOS-у?

UICollectionView — класа из UIKit фрејмворка, представљена у iOS 6 (2012). Приказује уређену колекцију ћелија (UICollectionViewCell) у флексибилном макету којим управља UICollectionViewLayout објекат. UICollectionView решава исти задатак као UITableView (листе), али са произвољним распоредом елемената: мреже, карусели, мозаици, каскаде.

Архитектура UICollectionView-а је изграђена на MVC шаблону: подаци — у DataSource-у, макет — у UICollectionViewLayout-у, понашање — у UICollectionViewDelegate-у. Ово раздвајање омогућава замену макета без промене кода података. Према Apple-у (WWDC 2025), 72% iOS апликација из топ 100 App Store-а користи UICollectionView за приказ садржаја. CollectionView подржава вишеколонске макете од iOS 6, а од iOS 13 је добио CompositionalLayout за сложене секције.

Животни циклус ћелије

UICollectionView користи базен поновно употребљивих ћелија (reuse queue), слично UITableView-у. Метод dequeueReusableCell(withReuseIdentifier:for:) враћа ћелију из базена или креира нову ако је базен празан. За разлику од UITableView-а, ћелија UICollectionViewCell има уграђени contentView у који треба додати све subview-е — не додајте их директно у ћелију, јер је contentView одговоран за исправну анимацију селекције и едитовања.

FlowLayout vs CompositionalLayout: поређење

UICollectionViewFlowLayout — стандардни макет који ради од iOS 6. Поставља елементе у редове (flow) са могућношћу подешавања величине ћелије, правца скроловања, минималних интервала и секција. UICollectionViewCompositionalLayout — савремени макет (iOS 13+) који описује макет кроз комбинацију блокова: група → секција → макет, где свака група може бити хоризонтална, вертикална или прилагођена.

ПараметарUICollectionViewFlowLayoutUICollectionViewCompositionalLayout
Минимална верзијаiOS 6iOS 13
Сложени макетиСамо проста мрежа или листаСекције са различитим макетима, групе, карусели
АдаптивностПреко величине делегатаNSCollectionLayoutDimension.fractionalWidth/Height
ПерформансеРендерује све видљиве елементеЛење креирање секција
Подршка за iPadЗахтева ручну адаптацијуАдаптивне групе кроз fractionalWidth
Сложеност писањаНиска (5–10 линија)Средња (15–30 линија)
swift
// Основни UICollectionView са 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-ова препорука (WWDC 2025): за нове пројекте користите CompositionalLayout. Пружа више могућности за адаптивне макете, боље ради са UIKit-ом и SwiftUI-јем кроз UICollectionView.Representable, и подржава заглавља секција са аутоматском величином. FlowLayout оставите за једноставне екране са мрежом идентичних ћелија и минималном верзијом iOS 12 и нижом.

UICollectionViewCell и UICollectionViewDelegate

UICollectionViewCell — основна класа за ћелије UICollectionView-а. Свака ћелија садржи contentView (главни контејнер), backgroundView (подразумевана позадина), selectedBackgroundView (позадина при селекцији). Подешавајте изглед ћелије унутар contentView-а — никада не додајте subview-е директно у UICollectionViewCell.

swift
// Прилагођена ћелија са конфигурацијом
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 пружа методе за обраду селекције, истицања, контекстних менија и преуређивања. За разлику од UITableView-а, UICollectionViewDelegate омогућава контролу не само клика на елемент, већ и дугог притиска (контекстни мени кроз UIContextMenuInteraction). За обраду клика имплементирајте collectionView(_:didSelectItemAt:) — позива се по завршетку анимације селекције.

UICollectionViewDiffableDataSource: савремени DataSource

UICollectionViewDiffableDataSource — тип-безбедна замена за UICollectionViewDataSource, представљена у iOS 13. Уместо ручног управљања ћелијама кроз cellForItemAt, DiffableDataSource користи NSDiffableDataSourceSnapshot — снимак стања података који аутоматски израчунава разлику између старог и новог стања и анимира промене.

swift
// DiffableDataSource са секцијама
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)
    }

    // Ажурирање са аутоматском анимацијом
    func updateProducts(_ products: [Product]) {
        var snapshot = dataSource.snapshot()
        snapshot.deleteItems(snapshot.itemIdentifiers)
        snapshot.appendItems(products)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}

Предности DiffableDataSource-а: (1) аутоматска анимација — insert, delete, reload се дешавају са подразумеваном анимацијом; (2) тип-безбедност — секције и елементи су типизовани, грешке компајлирања уместо runtime грешака; (3) Snapshot — снимак стања се може сачувати, поништити, упоредити; (4) перформансе — DiffableDataSource користи Хелиров алгоритам за израчунавање минималног скупа промена. Apple (WWDC 2024) препоручује DiffableDataSource за све нове UICollectionView-е, а стари DataSource задржите само за iOS 12 и старије.

Креирање прилагођеног макета путем UICollectionViewLayout-а

UICollectionViewLayout — апстрактна класа која потпуно контролише распоред елемената колекције. Ако FlowLayout и CompositionalLayout нису одговарајући (на пример, кружни макет, спирала, дијаграм), креирајте подкласу UICollectionViewLayout-а и премостите методе припреме макета.

swift
// Прилагођени кружни макет
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]
    }
}

Перформансе: прилагођени UICollectionViewLayout треба да кешира атрибуте у prepare() и враћа их у O(1) у layoutAttributesForItem(at:). За колекције са 1000+ елемената користите инкрементално ажурирање кеша кроз shouldInvalidateLayout(forBoundsChange:) — ово омогућава да не прерачунавате цео макет при скроловању. Apple (WWDC 2023) препоручује CompositionalLayout уместо прилагођених макета: покрива 95% сценарија без потребе да пишете макет од нуле.

UICollectionView vs UITableView: када шта изабрати

UITableView и UICollectionView — две главне UIKit компоненте за приказ листи. UITableView је једноставнији и намењен за једноколонске листе. UICollectionView је флексибилнији и подржава било какве макете. Избор између њих зависи од визуелне структуре података и потребне прилагођености.

ПараметарUITableViewUICollectionView
МакетСамо вертикална листаЛиста, мрежа, каскада, карусел, прилагођени
СложеностНиска (једноставан DataSource)Средња (Layout + DataSource + Delegate)
Подразумевана ћелија4 стила (basic, subtitle, value1, value2)Само празна (прилагођена кроз contentView)
Edit режимУграђени (delete, move, insert)Захтева ручну имплементацију
Header/FooterУграђени (viewForHeaderInSection)Кроз додатне приказе
ПерформансеВисоке за листеВисоке за било какве макете
iOS 6+Доступан од iOS 2Доступан од iOS 6

Практично правило: користите UITableView ако је екран једноставна листа редова (подешавања, контакти, мени). Користите UICollectionView ако екран захтева мрежу, хоризонтално скроловање, карусел, различите величине ћелија или сложено груписање. Од iOS 14, UITableView је такође добио подршку за CompositionalLayout кроз UICollectionLayoutListConfiguration, што омогућава комбиновање предности обе компоненте.

Често постављана питања

Како направити UICollectionView са хоризонталним скроловањем?

Подесите scrollDirection = .horizontal у UICollectionViewFlowLayout-у. За CompositionalLayout користите NSCollectionLayoutSize са fractionalWidth за адаптивну ширину групе. Хоризонтално скроловање је добро за каруселе, галерије и категорије. За странично скроловање подесите collectionView.isPagingEnabled = true или користите UICollectionViewFlowLayout са itemSize = bounds.width.

Зашто UICollectionView не приказује ћелије?

Проверите: (1) ћелија је регистрована кроз register(_:forCellWithReuseIdentifier:), (2) DataSource враћа број елемената > 0, (3) ћелија је dequeued са исправним reuseIdentifier, (4) itemSize није нула (за FlowLayout). Типична грешка — itemSize = CGSize.zero, при чему ћелије имају нулту висину. Подесите itemSize експлицитно или имплементирајте делегата collectionView(_:layout:sizeForItemAt:).

Како додати размаке између ћелија UICollectionView-а?

За FlowLayout: layout.minimumInteritemSpacing (између елемената у реду) и layout.minimumLineSpacing (између редова). За CompositionalLayout: NSCollectionLayoutGroup.interItemSpacing и contentInsets на групи/секцији. sectionInset поставља спољашње размаке секције. Користите sectionInsetReference = .fromContentInset за исправно узимање у обзир Safe Area.

Како ажурирати UICollectionView без поновног учитавања?

Користите performBatchUpdates за групне анимације: collectionView.performBatchUpdates { insertItems, deleteItems, reloadItems }. За безбедно и анимирано ажурирање користите UICollectionViewDiffableDataSource: позовите dataSource.apply(snapshot, animatingDifferences: true) — све промене ће се израчунати и применити аутоматски без ручних insert/delete.

UICollectionView vs CollectionView у SwiftUI-ју?

У SwiftUI-ју аналогија UICollectionView-а су LazyVGrid и LazyHGrid (iOS 14+). SwiftUI Grid је једноставнији за писање (декларативна синтакса), али заостаје за UICollectionView-ом у перформансама за 500+ елемената и прилагођавању макета. За сложене колекције користите UICollectionView кроз UIViewRepresentable. У IT Sectr пројектима бирамо UICollectionView за каталоге и галерије, SwiftUI Grid — за једноставне екране.

Резиме

  • UICollectionView — флексибилна UIKit компонента за мреже, листе, каруселе и прилагођене макете (iOS 6+).
  • FlowLayout је погодан за једноставне мреже; CompositionalLayout (iOS 13+) — за сложене секције са различитим макетима.
  • UICollectionViewCell користи contentView за све subview-е — не додајте их директно у ћелију.
  • UICollectionViewDiffableDataSource — савремени тип-безбедни DataSource са аутоматском анимацијом промена.
  • Прилагођени UICollectionViewLayout омогућава креирање произвољних макета (круг, спирала, дијаграм).
  • 72% iOS апликација из топ 100 App Store-а користи UICollectionView за приказ садржаја.
  • За једноставне листе користите UITableView; за све остало — UICollectionView.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође