Framework to manage complex UICollectionView
in declarative way and very few lines of code.
Heavily inspired by https://github.com/maxsokolov/TableKit and https://github.com/Instagram/IGListKit
- Via CocoaPods:
pod 'IVCollectionKit'
- Via Carthage
github "ivedeneev/CollectionKit"
- Via Swift Package Manager:
.package(url: "https://github.com/ivedeneev/CollectionKit", branch: "master")
- Declarative
UICollectionView
management - No need to implement
UICollectionViewDataSource
andUICollectionViewDelegate
- Easy way to map your models into cells
- Auto diffing
- Supports cells & reusable views from code and xibs and storyboard
- Flexible
- Register cells and reusable views automatically
- Fix scroll indicator clipping at iOS11 (http://www.openradar.me/34308893)
Key concepts of CollectionKit
are Section
, Item
and Director
.
Item
is responsible for UICollectionViewCell
configuration, size and actions
Section
is responsible for group of items and provides information for each item, header/footer and all kind of insets/margins: section insets, minimum inter item spacing and line spacing
Director
is responsible for providing all information, needed for UICollectionView
and its updations
Setup UICollectionView and director:
Setup collection view
collectionView = UICollectionView(frame: view.bounds, colletionViewLayout: UICollectionViewFlowLayout())
collectionDirector = CollectionDirector(colletionView: collectionView)
Create items
let item1 = CollectionItem<CollectionCell>(item: "hello!")
let item2 = CollectionItem<CollectionCell>(item: "im")
let item3 = CollectionItem<CollectionCell>(item: "ColletionKit")
let item4 = CollectionItem<ImageCell>(item: "greeting.png")
Create section and put items in section
let section = CollectionSection()
let items = [item1, item2, item3, item4]
section += items
director += section
Put section in director and reload director
director += section
director.reload()
Cell must implement ConfigurableCollectionCell
protocol. You need to specify cell size and configuration methods:
extension CollectionCell : ConfigurableCollectionItem {
static func estimatedSize(item: String, boundingSize: CGSize, in section: AbstractCollectionSection) -> CGSize {
return CGSize(width: boundingSize.width - 40, height: 44)
}
func configure(item: String) {
textLabel.text = item
}
}
Note, that `contentInsets` value of collection view is respected in `boundingSize` parameter
Framework doesnt support auto-sizing cells, but you can adjust cell width and height to collection view dimensions
let item = CollectionItem<CollectionCell>(item: "text").adjustsWidth(true)
It means that width of this cell will be equal to collectionView.bounds.width
minus collectionView content insets and section insets. width from estimatedSize
method is ignored for this case. adjustsHeight(Bool)
method has same logic, but for vertical insets.
Implement such actions like didSelectItem
or shouldHighlightItem
using functional syntax
let row = CollectionItem<CollectionCell>(item: "text")
.onSelect({ (_) in
print("i was tapped!")
}).onDisplay({ (_) in
print("i was displayed")
})
Available actions:
onSelect
onDeselect
onDisplay
onEndDisplay
onHighlight
onUnighlight
shouldHighlight
You can setup inter item spacing, line spacing and section insets using section object:
let section = CollectionSection()
section.minimumInterItemSpacing = 2
section.insetForSection = UIEdgeInsetsMake(0, 20, 0, 20)
section.lineSpacing = 2
Also you can set section header and footer:
section.headerItem = CollectionHeaderFooterView<SectionHeader>(item: "This is header")
section.footerItem = CollectionHeaderFooterView<SectionHeader>(item: "This is footer")
IVCollectionKit
provides 2 ways for updatung UICollectionView
content:
- reload (using
reloadData
) - animated updates(using
performBatchUpdates
)
Note, that all models, that you use in CollectionItem
initializations should conform Hashable
protocol. Framework provides fallback for non-hashable models, but it may cause unexpected behaviour during animated updates.
director.performUpdates()
director.performUpdates { finished: Bool in
print("updates completed")
}
If you need to animate cell size you can use `director.setNeedsUpdates()` method. This method doesnt trigger cell calculatuion under the hood
IMPORTANT! if you use animated updates via performUpdates
or setNeedsUpdate
dont use update methods of UICollectionView directly. It may lead to unpredictable behaviour
IVCollectionView
is experemental UICollectionView
subclass designed to manage incorrect updates. You can use it instead of ordinary CollectionView. Typical use case is many simultanious updates.
You can provide your own section implementation using AbstractCollectionSection
protocol. For example, you can use it for using CollectionDirector
with Realm.Results
and save Results
lazy behaviour or implementing expandable sections (see exapmles). Also you can create subclass of CollectionSection
if you dont need radically different behaviour
If you need to implement UISrollViewDelegate
methods for your collection view (e.g pagination support) you can use scrollDelegate
property
final class ViewController: UIViewController, UIScrollViewDelegate {
var director: CollectionDirector!
...
private func setupDirector() {
director.scrollDelegate = self
}
}