A lightweight and reusable framework for UICollectionView written in Swift.
It provides a generic, type-safe, and highly customizable way to manage collection view data, section headers, delegates, and layouts. Compatible with Swift 5.9+ / iOS 14+.
- ✅ Generic and reusable
UICollectionViewDataSource - ✅ Generic and reusable
UICollectionViewDelegate - ✅ Generic and reusable
UICollectionViewCompositionalLayout - ✅ Clean protocol-oriented architecture
- ✅ Supports dynamic section headers (titles + buttons)
- ✅ Strongly typed, type-safe, and fully generic
- ✅ Predefined layout templates for common scenarios
- ✅ Minimal boilerplate with default implementations
| Feature | Description |
|---|---|
| 🧩 Type Safety | Strong typing everywhere ensures no AnyObject confusion |
| ⚡ Reusable | Write once, reuse across multiple collection views, headers, delegates, and layouts |
| 🧼 Clean Architecture | Separates data, layout, delegate, and UI logic |
| 🧠 Extensible | Easily extend with default methods, custom buttons, or layout templates |
A customizable section header that supports a title ,optional action buttons and optional icon for title, making it easy to display section information dynamically.
-
A dynamic title (bold, resizable font)
-
Optiona left-aligned icon
-
Optional right-aligned buttons (e.g., “All List”, custom actions)
-
Auto-layout with UIStackView
-
Button tap callback closure
Defines the icon displayed next to the title.
public enum TitleIconType { case systemImage(String) // SF Symbols case imageAsstes(String) // Asset Catalog images } public struct HeaderIcon { public let image: TitleIconType public let tintColor: HeaderItemColor }The main configuration model for CHeaderView.
public struct HeaderViewItem { public let title: String // Header title text public var icon: HeaderIcon? // Optional title icon public let sizeType: SectionSizeType // Header size / font style public var buttonTypes: [TitleForSectionButtonType] // Action buttons displayed on the right } header.configure(with: .init( title: item.title, icon: item.icon, sizeType: item.sizeType, buttonTypes: item.buttonTypes)) { [weak self] tappedType in guard let self else { return } source.onTappedTitleButton(buttonType: tappedType, section: indexPath.section) }A protocol-oriented, type-safe, and reusable approach for managing collection view data.
Defines a clean contract for UICollectionView data handling — sections, cells, and optional headers.
public protocol GenericCollectionDataSourceProtocol { associatedtype CellItem func numberOfSections() -> Int func numberOfRowsInSection(in section: Int) -> Int func cellForItem(section: Int, item: Int) -> CellItem func cellIdentifier(at section: Int) -> String func titleForSection(at section: Int) -> ( title: String, sizeType: SectionSizeType, buttonType: [TitleForSectionButtonType]? ) func onTappedTitleButton(buttonType: TitleForSectionButtonType, section: Int) }func titleForSection(at section: Int) -> HeaderViewItem func onTappedTitleButton(buttonType: TitleForSectionButtonType, section: Int) { } }SectionSizeType Controls the font size for section titles:
public enum SectionSizeType { case large, medium, small var size: CGFloat { ... } }TitleForSectionButtonType Represents possible header button types:
public enum TitleForSectionButtonType { case allList case custom(String) var title: String { ... } }struct MyModel { let name: String } final class MyCollectionDataSource: GenericCollectionDataSourceProtocol { typealias CellItem = MyModel func numberOfSections() -> Int { 2 } func numberOfRowsInSection(in section: Int) -> Int { 5 } func cellForItem(section: Int, item: Int) -> MyModel { MyModel(name: "Item \(item)") } func cellIdentifier(at section: Int) -> String { "MyCell" } func titleForSection(at section: Int) -> ( title: String, sizeType: SectionSizeType, buttonType: [TitleForSectionButtonType]? ) { (title: "Section \(section)", sizeType: .medium, buttonType: [.allList, .custom("Filter")]) } func onTappedTitleButton(buttonType: TitleForSectionButtonType, section: Int) { print("Tapped \(buttonType) in section \(section)") } }let mySource = MyCollectionDataSource() let dataSource = GenericCollectionDataSource(source: mySource) { identifier, cell, item in guard let cell = cell as? MyCollectionViewCell, let model = item as? MyModel else { return } cell.configure(with: model) } collectionView.dataSource = dataSourceA lightweight and reusable UICollectionView delegate written in Swift. It provides a generic, type-safe, and protocol-oriented way to handle item selection and scroll events in collection views.
public protocol GenericCollectionDelegateSourceProtocol { func didSelectItem(section: Int, item: Int) func scrollViewDidScroll(endOfPage: Bool) }public extension GenericCollectionDelegateSourceProtocol { func scrollViewDidScroll(endOfPage: Bool) { } func didSelectItem(section: Int, item: Int) { } }final class MyDelegateSource: GenericCollectionDelegateSourceProtocol { func didSelectItem(section: Int, item: Int) { print("Selected item \(item) in section \(section)") } func scrollViewDidScroll(endOfPage: Bool) { if endOfPage { print("Reached end of page ✅") } } }let source = MyDelegateSource() let delegate = GenericCollectionDelegate(source: source) collectionView.delegate = delegateA lightweight and reusable UICollectionViewCompositionalLayout framework written in Swift. Provides a generic, type-safe, and flexible way to configure collection view layouts.
public protocol GenericCollectionLayoutProviderProtocol { func layout(for sectionIndex: Int) -> LayoutSource }Describes the structure and behavior of the layout:
public struct LayoutSource { public init(groupOrientation: ScrollDirection, itemSize: SizeInfo, groupSize: SizeInfo, sectionInsets: (top: CGFloat, leading: CGFloat, bottom: CGFloat, trailing: CGFloat), interItemSpacing: CGFloat, interGroupSpacing: CGFloat, scrollDirection: ScrollDirection) { ... } }public enum DimensionType { case fractional, absolute, none } public struct SizeInfo { let width: (type: DimensionType, value: CGFloat) let height: (type: DimensionType, value: CGFloat) } public enum ScrollDirection { case horizontal, vertical }final class MyLayoutSource: GenericCollectionLayoutProviderProtocol { func layout(for sectionIndex: Int) -> LayoutSource { switch sectionIndex { case 0: return LayoutSourceTeamplate.horizontalSingleRow.template case 1: return LayoutSourceTeamplate.verticalTwoPerRow.template default: return LayoutSourceTeamplate.none.template } } } let layoutProvider = GenericCollectionLayoutProvider(source: MyLayoutSource()) let layout = layoutProvider.createLayout() let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) GenericCollectionViewKit.mov | GenericCollectionView.mov |
dependencies: [ .package(url: "https://github.com/engingulek/GenericCollectionViewKit.git", from: "0.0.2") ]