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")
]