/CollectionViewTools

Effective framework for making your UICollectionView usage simple and comfortable

Primary LanguageSwiftMIT LicenseMIT

CollectionViewTools

Platform Swift Version Carthage Compatible CocoaPods Compatible SPM Compatible PRs Welcome

Effective framework, similar to TableViewTools for making your UICollectionView usage simple and comfortable. It allows you to move UICollectionView configuration and interaction logic to separated objects and simply register, add and remove cells from the collection view.



Features

  • Separate layer that synchronizes data with the cell appearance
  • Full implementation of UICollectionViewDelegate and UICollectionViewDataSource under the hood
  • Support of protocols and subclasses as data models

Requirements

  • iOS 8.2+
  • Xcode 8.0+

Installation

Carthage

Create a Cartfile that lists the framework and run carthage update. Follow the instructions to add the framework to your project.

github "rosberry/CollectionViewTools"

CocoaPods

You can use CocoaPods to install CollectionViewTools by adding it to your Podfile:

platform :ios, '8.2'
use_frameworks!
pod 'CollectionViewTools'

Manually

Drag Sources folder from last release into your project.

Usage

Creating manager

let manager = CollectionViewManager(collectionView: collectionView)

Creating section

let titles = ["Item 1", "Item 2", "Item 3"]
var cellItems = titles.map { title in
    return ExampleCollectionViewCellItem(title: title)
}
let sectionItem = GeneralCollectionViewSectionItem(cellItems: cellItems)
manager.sectionItems = [sectionItem]

Cell item implementation

class ExampleCollectionViewCellItem: CollectionViewCellItem {
    
    typealias Cell = ExampleCollectionViewCell
    private(set) var reuseType: ReuseType = .class(Cell.self)
    
    private let title: String
    
    init(title: String) {
        self.title = title
    }
    
    func configure(_ cell: UICollectionViewCell) {
        guard let cell = cell as? Cell else {
            return
        }
        cell.titleLabel.text = title
    }
    
    func size() -> CGSize {
        return CGSize(width: 100, height: 40)
    }
}

Using cached size

You can use cached size for optimisation. To do that you should return cachedSize value in size method. Keep in mind cached size will be set once and never be invalidated automatically so if you need to update cell size you should invalidate cachedSize by yourself.

    func invalidateCachedSize() {
        cachedSize = nil
    }
    func size() -> CGSize {
        return cachedSize ?? CGSize(width: 100, height: 40)
    }

Diffs

CollectionViewTools support "diffs". It means that CollectionViewManager can calculate difference between old and new section items and animate collection view sections and cells accordingly.

To work with diffs all cell items must conform DiffItem protocol:

public protocol DiffItem {
    var diffIdentifier: String { get }
    func isEqual(to item: DiffItem) -> Bool
}

diffIdentifier is used to identify items to find out which items should be inserted, deleted or moved (note that it must be unique(!!!), otherwise diff algorithm can work incorrectly). isEqual is used to compare items with same diffIdentifier to find out which items should be updated.

Cell item implementation

class ExampleCollectionViewCellItem: CollectionViewCellItem, DiffItem {
        
    // MARK: - DiffItem
    
    var diffIdentifier: String = ""

    func isEqual(to item: DiffItem) -> Bool {
        guard let item = item as? ExampleCollectionViewCellItem else {
            return false
        }
        return title == item.title
    }

    // implementation...
}

For section items you can use GeneralCollectionViewDiffSectionItem or create your own section items that conforms DiffSectionItem protocol.

Creating section

struct Object {
    let id: UInt
    let title: String
}

let objects = [Object(id: 1, title: "Item 1"),
               Object(id: 2, title: "Item 2"), 
               Object(id: 3, title: "Item 3")]
               
var cellItems = objects.map { object -> ExampleCollectionViewCellItem in
    let cellItem = ExampleCollectionViewCellItem(title: object.title)
    cellItem.diffIdentifier = "\(object.id)"
    return cellItem
}

let sectionItem = GeneralCollectionViewDiffSectionItem(cellItems: cellItems)
sectionItem.diffIdentifier = "main" 

let manager = CollectionViewManager(collectionView: collectionView)
manager.update(with: [sectionItem], animated: true)

Diff adaptors

CollectionViewManager uses DeepDiff to calculate difference between items. But if you want to use other diff libraries (for example IGListKit, Dwifft, etc.) or your own diff algorithm you can create adaptor that conforms CollectionViewDiffAdaptor protocol.

let adaptor = CollectionViewIGListKitDiffAdaptor()
manager.update(with: [sectionItem], diffAdaptor: adaptor, animated: true)

Authors

About

This project is owned and maintained by Rosberry. We build mobile apps for users worldwide 🌏.

Check out our open source projects, read our blog or give us a high-five on 🐦 @rosberryapps.

License

Product Name is available under the MIT license. See the LICENSE file for more info.