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. این تقسیم‌بندی امکان تعویض طرح‌ها را بدون تغییر کد داده‌ها فراهم می‌کند. به گفته اپل (WWDC 2025)، 72% از برنامه‌های iOS در ۱۰۰ اپ برتر App Store از UICollectionView برای نمایش محتوا استفاده می‌کنند. CollectionView از iOS 6 از طرح‌های چندستونی پشتیبانی می‌کند و از iOS 13 CompositionalLayout را برای بخش‌های پیچیده دریافت کرد.

چرخه حیات سلول

UICollectionView مانند UITableView از یک مخزن سلول‌های قابل استفاده مجدد (reuse queue) استفاده می‌کند. متد dequeueReusableCell(withReuseIdentifier:for:) یک سلول از مخزن برمی‌گرداند یا اگر مخزن خالی باشد سلول جدیدی ایجاد می‌کند. برخلاف UITableView، سلول UICollectionViewCell دارای contentView داخلی است که همه زیرنمای‌ها باید به آن اضافه شوند — آنها را مستقیماً به سلول اضافه نکنید، زیرا contentView مسئول انیمیشن صحیح انتخاب و ویرایش است.

FlowLayout در مقابل CompositionalLayout: مقایسه

UICollectionViewFlowLayout — طرح استانداردی که از iOS 6 کار می‌کند. عناصر را در ردیف‌ها (flow) با امکان تنظیم اندازه سلول، جهت اسکرول، حداقل فاصله‌ها و بخش‌ها قرار می‌دهد. UICollectionViewCompositionalLayout — طرح مدرن (iOS 13+) که طرح را از طریق ترکیب بلوک‌ها توصیف می‌کند: گروه ← بخش ← طرح، که در آن هر گروه می‌تواند افقی، عمودی یا سفارشی باشد.

پارامترUICollectionViewFlowLayoutUICollectionViewCompositionalLayout
حداقل نسخهiOS 6iOS 13
طرح‌های پیچیدهفقط شبکه یا لیست سادهبخش‌هایی با طرح‌های مختلف، گروه‌ها، چرخ‌فلک‌ها
سازگاریاز طریق اندازه دلیگیتNSCollectionLayoutDimension.fractionalWidth/Height
عملکردتمام عناصر قابل مشاهده را رندر می‌کندایجاد تنبل بخش‌ها
پشتیبانی iPadنیاز به تطبیق دستی داردگروه‌های تطبیقی از طریق fractionalWidth
سختی نوشتنکم (۵–۱۰ خط)متوسط (۱۵–۳۰ خط)
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
    }
}

توصیه اپل (WWDC 2025): برای پروژه‌های جدید از CompositionalLayout استفاده کنید. امکانات بیشتری برای طرح‌های تطبیقی فراهم می‌کند، با UIKit و SwiftUI از طریق UICollectionView.Representable بهتر کار می‌کند و از هدرهای بخش با اندازه خودکار پشتیبانی می‌کند. FlowLayout را برای صفحه‌های ساده با شبکه سلول‌های یکسان و حداقل نسخه iOS 12 و پایین‌تر保留 کنید.

UICollectionViewCell و UICollectionViewDelegate

UICollectionViewCell — کلاس پایه برای سلول‌های UICollectionView. هر سلول شامل contentView (کانتینر اصلی)، backgroundView (پس‌زمینه پیش‌فرض)، selectedBackgroundView (پس‌زمینه هنگام انتخاب) است. ظاهر سلول را در داخل contentView تنظیم کنید — هرگز زیرنماها را مستقیماً به 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: منبع داده مدرن

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: (۱) انیمیشن خودکار — insert، delete، reload با انیمیشن پیش‌فرض انجام می‌شوند؛ (۲) امنیت نوع — بخش‌ها و عناصر تایپ‌شده هستند، خطاهای کامپایل به جای خطاهای runtime؛ (۳) Snapshot — تصویر وضعیت قابل ذخیره، بازگردانی و مقایسه است؛ (۴) عملکرد — DiffableDataSource از الگوریتم هلییر برای محاسبه حداقل مجموعه تغییرات استفاده می‌کند. اپل (WWDC 2024) DiffableDataSource را برای همه UICollectionViewهای جدید توصیه می‌کند و DataSource قدیمی را فقط برای iOS 12 و قدیمی‌تر保留 کنید.

ایجاد طرح سفارشی از طریق UICollectionViewLayout

UICollectionViewLayout — کلاس انتزاعی که به طور کامل چیدمان عناصر مجموعه را کنترل می‌کند. اگر FlowLayout و CompositionalLayout مناسب نیستند (مثلاً طرح دایره‌ای، مارپیچ، نمودار)، یک زیرکلاس از UICollectionViewLayout ایجاد کنید و متدهای آماده‌سازی طرح را override کنید.

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() کش کرده و در layoutAttributesForItem(at:) با O(1) بازگرداند. برای مجموعه‌های با ۱۰۰۰+ عنصر از به‌روزرسانی افزایشی کش از طریق shouldInvalidateLayout(forBoundsChange:) استفاده کنید — این کار باعث می‌شود در هنگام اسکرول کل طرح دوباره محاسبه نشود. اپل (WWDC 2023) CompositionalLayout را به جای طرح‌های سفارشی توصیه می‌کند: ۹۵% سناریوها را بدون نیاز به نوشتن طرح از صفر پوشش می‌دهد.

UICollectionView در مقابل UITableView: چه زمانی چه چیزی را انتخاب کنیم

UITableView و UICollectionView — دو کامپوننت اصلی UIKit برای نمایش لیست‌ها. UITableView ساده‌تر است و برای لیست‌های تک‌ستونی طراحی شده. UICollectionView انعطاف‌پذیرتر است و از هر نوع طرحی پشتیبانی می‌کند. انتخاب بین آنها به ساختار بصری داده‌ها و سفارشی‌سازی مورد نیاز بستگی دارد.

پارامترUITableViewUICollectionView
طرحفقط لیست عمودیلیست، شبکه، آبشاری، چرخ‌فلک، سفارشی
پیچیدگیکم (DataSource ساده)متوسط (Layout + DataSource + Delegate)
سلول پیش‌فرض۴ سبک (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 سلول‌ها را نمایش نمی‌دهد؟

بررسی کنید: (۱) سلول از طریق register(_:forCellWithReuseIdentifier:) ثبت شده است، (۲) DataSource تعداد عناصر > ۰ را برمی‌گرداند، (۳) سلول با reuseIdentifier صحیح dequeued شده است، (۴) itemSize صفر نیست (برای FlowLayout). خطای معمول — itemSize = CGSize.zero که باعث می‌شود سلول‌ها ارتفاع صفر داشته باشند. itemSize را به صراحت تنظیم کنید یا دلیگیت collectionView(_:layout:sizeForItemAt:) را پیاده‌سازی کنید.

چگونه بین سلول‌های UICollectionView فاصله اضافه کنیم؟

برای FlowLayout: layout.minimumInteritemSpacing (بین عناصر در یک ردیف) و layout.minimumLineSpacing (بین ردیف‌ها). برای CompositionalLayout: NSCollectionLayoutGroup.interItemSpacing و contentInsets روی گروه/بخش. sectionInset فاصله‌های خارجی بخش را مشخص می‌کند. برای در نظر گرفتن صحیح Safe Area از sectionInsetReference = .fromContentInset استفاده کنید.

چگونه UICollectionView را بدون بارگذاری مجدد به‌روز کنیم؟

از performBatchUpdates برای انیمیشن‌های گروهی استفاده کنید: collectionView.performBatchUpdates { insertItems, deleteItems, reloadItems }. برای به‌روزرسانی امن و انیمیشن‌دار از UICollectionViewDiffableDataSource استفاده کنید: dataSource.apply(snapshot, animatingDifferences: true) را فراخوانی کنید — همه تغییرات به طور خودکار محاسبه و بدون insert/delete دستی اعمال می‌شوند.

UICollectionView در مقابل CollectionView در SwiftUI؟

در SwiftUI معادل UICollectionView LazyVGrid و LazyHGrid هستند (iOS 14+). SwiftUI Grid از نظر نوشتن ساده‌تر است (سینتکس اعلانی)، اما در عملکرد برای ۵۰۰+ عنصر و سفارشی‌سازی طرح‌ها از UICollectionView پایین‌تر است. برای مجموعه‌های پیچیده از UICollectionView از طریق UIViewRepresentable استفاده کنید. در پروژه‌های IT Sectr برای کاتالوگ‌ها و گالری‌ها UICollectionView را انتخاب می‌کنیم و برای صفحه‌های ساده SwiftUI Grid را.

خلاصه

  • UICollectionView — کامپوننت انعطاف‌پذیر UIKit برای شبکه‌ها، لیست‌ها، چرخ‌فلک‌ها و طرح‌های سفارشی (iOS 6+).
  • FlowLayout برای شبکه‌های ساده مناسب است؛ CompositionalLayout (iOS 13+) برای بخش‌های پیچیده با طرح‌های مختلف.
  • UICollectionViewCell از contentView برای همه زیرنماها استفاده می‌کند — آنها را مستقیماً به سلول اضافه نکنید.
  • UICollectionViewDiffableDataSource — منبع داده مدرن امن از نظر نوع با انیمیشن خودکار تغییرات.
  • UICollectionViewLayout سفارشی امکان ایجاد طرح‌های دلخواه (دایره، مارپیچ، نمودار) را فراهم می‌کند.
  • ۷۲% از برنامه‌های iOS در ۱۰۰ اپ برتر App Store از UICollectionView برای نمایش محتوا استفاده می‌کنند.
  • برای لیست‌های ساده از UITableView استفاده کنید؛ برای بقیه موارد — UICollectionView.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید