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 χρησιμοποιεί τον αλγόριθμο Hellir για υπολογισμό του ελάχιστου συνόλου αλλαγών. Η 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)
Λειτουργία επεξεργασίαςΕνσωματωμένη (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) το κελί έχει γίνει dequeue με σωστό 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. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης