voyages-sncf-technologies / Collor

Licence: bsd-3-clause
A declarative-ui framework for UICollectionView with great and useful features.

Programming Languages

swift
15916 projects
declarative
70 projects

Projects that are alternatives of or similar to Collor

Lpdmvvmkit
LPDMvvmKit - Elegant MVVM framework in Objective-C.
Stars: ✭ 400 (+119.78%)
Mutual labels:  mvvm, viewmodel, uicollectionview
Abexpandableview
Expandable, collapsible, filterable and single/multi selectable table view.
Stars: ✭ 138 (-24.18%)
Mutual labels:  cocoapods, mvvm
Restapimvvm
App that interacts with a Rest Api. Architecture is MVVM.
Stars: ✭ 130 (-28.57%)
Mutual labels:  mvvm, viewmodel
Stickyheaderflowlayout
Sticky headers for UICollectionView written in pure Swift (based on CSStickyHeaderFlowLayout)
Stars: ✭ 144 (-20.88%)
Mutual labels:  cocoapods, uicollectionview
Rglistkit
RGListKit is a Protocol & MVVM based framework to easily populate a UITableView or UICollectionView via single api.
Stars: ✭ 178 (-2.2%)
Mutual labels:  mvvm, uicollectionview
Movieapp Clean Architecture
Learning Project (Movie App) For Applying Android Architecture Components And Clean Architecture Using MVVM With Kotlin
Stars: ✭ 123 (-32.42%)
Mutual labels:  mvvm, viewmodel
Popularmovies
🎥 Movie discovery app showcasing Android best practices with Google's recommended architecture: MVVM + Repository + Offline support + Android Architecture Components + Paging library & Retrofit2.
Stars: ✭ 142 (-21.98%)
Mutual labels:  mvvm, viewmodel
Akane
Lightweight native iOS MVVM framework
Stars: ✭ 92 (-49.45%)
Mutual labels:  mvvm, viewmodel
Ktarmor Mvvm
👻 Android快速开发框架, KtArmor 寓意着 为Android 赋予战斗装甲, 方便开发者快速进行Android 开发。
Stars: ✭ 148 (-18.68%)
Mutual labels:  mvvm, viewmodel
Coolweather
Weather App that uses Android best practices. Android Jetpack, clean architecture. Written in Kotlin
Stars: ✭ 154 (-15.38%)
Mutual labels:  mvvm, viewmodel
Iglistkit
A data-driven UICollectionView framework for building fast and flexible lists.
Stars: ✭ 12,196 (+6601.1%)
Mutual labels:  diffing, uicollectionview
Mentorship Android
Mentorship System is an application that matches women in tech to mentor each other, on career development, through 1:1 relations during a certain period of time. This is the Android application of this project.
Stars: ✭ 117 (-35.71%)
Mutual labels:  mvvm, viewmodel
Lightweightobservable
📬 A lightweight implementation of an observable sequence that you can subscribe to.
Stars: ✭ 114 (-37.36%)
Mutual labels:  cocoapods, mvvm
Android Mvvm Architecture
A basic sample android application to understand MVVM in a very simple way.
Stars: ✭ 129 (-29.12%)
Mutual labels:  mvvm, viewmodel
Aachulk
️🔥️🔥️🔥AACHulk是以Google的ViewModel+DataBinding+LiveData+Lifecycles框架为基础, 结合Okhttp+Retrofit+BaseRecyclerViewAdapterHelper+SmartRefreshLayout+ARouter打造的一款快速MVVM开发框架
Stars: ✭ 109 (-40.11%)
Mutual labels:  mvvm, viewmodel
Closures
Swifty closures for UIKit and Foundation
Stars: ✭ 1,720 (+845.05%)
Mutual labels:  cocoapods, uicollectionview
Campcotcollectionview
Collapse and expand UICollectionView sections with one method call.
Stars: ✭ 161 (-11.54%)
Mutual labels:  cocoapods, uicollectionview
Easychatandroidclient
EasyChat是一个开源的社交类的App。主要包含消息、好友、群组等相关的IM核心功能。部分界面参照了QQ、微信等相关社交APP。EasyChat APP整体采用MVVM模式,基于JetPack(Lifecycle,LiveData,ViewModel,Room)构建
Stars: ✭ 64 (-64.84%)
Mutual labels:  mvvm, viewmodel
Sample Code Movies
This repository contains sample code. Its purpose being, to quickly demonstrate Android and software development in general, clean code, best practices, testing and all those other must know goodies.
Stars: ✭ 81 (-55.49%)
Mutual labels:  mvvm, viewmodel
Android Vmlib
VMLib is an Android framework based on Android Jetpack, easy to use, desinged for fast development. Embrace the new way devloping Android :)
Stars: ✭ 146 (-19.78%)
Mutual labels:  mvvm, viewmodel

Collor logo

CI Status Coverage Status Version License Platform

About

Collor is a MVVM data-oriented framework for accelerating, simplifying and ensuring UICollectionView building.
Collor was created for and improved in the Voyages-sncf.com app.

Features

Here is the list of all the features:

  • [x] Easy to use.
  • [x] A readable collectionView model.
  • [x] Architectured for reusing cell.
  • [x] Protocol / Struct oriented.
  • [x] Scalable.
  • [x] Never use IndexPath.
  • [x] Never register a cell.
  • [x] Update the collectionView model easily.
  • [x] Diffing data or section(s)
  • [x] Diffing handles deletes, inserts, moves and updates
  • [x] Manage decoration views in our custom layout easily.
  • [x] Make easier building custom layout.
  • [x] Swift 4 (use 1.0.x for swift 3 compatibility).
  • [x] Well tested.
  • [x] 🆕 Handle supplementary views (may be improved in next versions)

Collor Random Sample Collor Weather Sample

Getting started

Example

To run the example project, clone the repo, and run pod install from the Example directory first.
There are 4 examples:

  • Menu : Simple collectionView with userEvent propagation example
  • Random : Diffing entire data + custom layout
  • Weather : Diffing sections + custom layout
  • Pantone : Adding and remove items using CollectionDatas.
  • RealTime : Complex diffing (insert, delete, reload) + custom layout handling with DecorationViewHandler.
  • Alphabet : An example with a supplementaryView + custom layout handling with SupplementaryViewsHandler.

Usage

The UICollectionView is represented by a collectionData object which contains sectionDescriptors which contain themself cellDescriptors. Each item or cell in Collor is composed by 3 objects:

  • The UICollectionViewCell (XIB or not + swift file) which implements CollectionCellAdaptable
  • A cellDescriptor which implements CollectionCellDescribable
  • An adapter (view model) which implements CollectionAdapter
CellDescriptor

It describes the cell and is the link between the cell and the viewModel. Logically, one type of cell needs only one cellDescriptor. It owns the cell identifier, the cell className and handles the size of the cell. The collectionData handles cell registering and dequeuing using these properties.

final class WeatherDayDescriptor: CollectionCellDescribable {

    let identifier: String = "WeatherDayCollectionViewCell"
    let className: String = "WeatherDayCollectionViewCell"
    var selectable:Bool = false

    let adapter: WeatherDayAdapter

    init(adapter: WeatherDayAdapter) {
        self.adapter = adapter
    }

    func size(_ collectionView: UICollectionView, sectionDescriptor: CollectionSectionDescribable) -> CGSize {
        let sectionInset = sectionDescriptor.sectionInset(collectionView)
        let width:CGFloat = collectionView.bounds.width - sectionInset.left - sectionInset.right
        return CGSize(width:width, height:60)
    }

    public func getAdapter() -> CollectionAdapter {
        return adapter
    }
}
Adapter

An adapter is a viewModel object. It transforms your model in a human readable data used by the cell.

struct WeatherDayAdapter: CollectionAdapter {

    let date: NSAttributedString

    static let dateFormatter: DateFormatter = {
        let df = DateFormatter()
        df.dateFormat = "EEEE d MMMM"
        return df
    }()

    init(day:WeatherDay) {

        let dateString = WeatherDayAdapter.dateFormatter.string(from: day.date)
        date = NSAttributedString(string: dateString, attributes: [
            NSFontAttributeName: UIFont.boldSystemFont(ofSize: 18),
            NSForegroundColorAttributeName: UIColor.black
        ])
    }
}

When a cell is dequeued, the collectionData updates the cell with this object.

final class WeatherDayCollectionViewCell: UICollectionViewCell, CollectionCellAdaptable {
  @IBOutlet weak var label: UILabel!

  func update(with adapter: CollectionAdapter) {
        guard let adapter = adapter as? WeatherDayAdapter else {
            fatalError("WeatherDayAdapter required")
        }
        label.attributedText = adapter.date
    }
}
ViewController

Create the dataSource and the delegate:

lazy var collectionViewDelegate: CollectionDelegate = CollectionDelegate(delegate: self)
lazy var collectionViewDatasource: CollectionDataSource = CollectionDataSource(delegate: self)

Create the collectionData:

let collectionData = MyCollectionData()

Bind the collectionView with the data, the datasource and the delegate:

bind(collectionView: collectionView, with: collectionData, and: collectionViewDelegate, and: collectionViewDatasource)

Create a section and one cell in the collectionData:

final class MyCollectionData : CollectionData {

    override func reloadData() {
        super.reloadData()

        let section = MySectionDescriptor().reloadSection { (cells) in
                let cell = MyColorDescriptor(adapter: MyColorAdapter(model: "someThing"))
                cells.append(cell)
            })
        }
        sections.append(section)
    }
}

MySectionDescriptor:

final class MySectionDescriptor : CollectionSectionDescribable {

  func sectionInset(_ collectionView: UICollectionView) -> UIEdgeInsets {
      return UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
  }
}

You get a readable data which represents your UICollectionView, without code duplication, reusing cell and with a good separation of code.

SupplementatyView

To add a supplementaryView, instead of using CollectionSectionDescribable.reloadSection(:), call CollectionSectionDescribable.reload(:). The builder passed as parameter exposes new method to add a supplementaryView easily.

Collor Alphabet Sample

let section = MySectionDescriptor().reload { builder in
    let letterAdapter = LetterAdapter(letter: "A")
    let letterDescriptor = LetterCollectionReusableViewDescriptor(adapter: letterAdapter)
    builder.add(supplementaryView: letterDescriptor, kind: "letter")
}
sections.append(section)

CollectionSupplementaryViewDescribable behaves like a CollectionCellDescribable. It needs an adapter to fill the view with data. But, for displaying a supplementaryView correctly, a custom layout is required in order to set attributes for the supplementaryViews created in the CollectionData. As with decorationViews, Collor provides aSupplementaryViewsHandler` object to manage supplementaryViews. It handles addition, caching and updatating.

class Layout : UICollectionViewFlowLayout {
    //...
    override func prepare() {
        super.prepare()
        
        supplementaryViewsHandler.prepare()
        
        for (sectionIndex, sectionDescriptor) in datas.sections.enumerated() {
            
            let firstCellIndexPath = IndexPath(item: 0, section: sectionIndex)
            let firstCellAttributes = layoutAttributesForItem(at: firstCellIndexPath)!
            
            sectionDescriptor.supplementaryViews.forEach { (kind, views) in
                
                views.enumerated().forEach { (index, viewDescriptor) in
                    let indexPath = IndexPath(item: index, section: sectionIndex)
                    let a = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: kind, with: indexPath)
                    a.frame = viewDescriptor.frame(collectionView, sectionDescriptor: sectionDescriptor)
                    a.frame.origin.y += firstCellAttributes.frame.origin.y
                    
                    supplementaryViewsHandler.add(attributes: a)
                }
            }
        }
    }
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElements(in: rect)
        let supplementaryAttributes = supplementaryViewsHandler.attributes(in: rect)
        if let attributes = attributes {
            return attributes + supplementaryAttributes
        }
        return attributes
    }
    
    override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return supplementaryViewsHandler.attributes(for: elementKind, at: indexPath)
    }
    
    override func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem]) {
        super.prepare(forCollectionViewUpdates: updateItems)
        supplementaryViewsHandler.prepare(forCollectionViewUpdates: updateItems)
    }
    
    override func indexPathsToInsertForSupplementaryView(ofKind elementKind: String) -> [IndexPath] {
        return supplementaryViewsHandler.inserted(for: elementKind)
    }
    
    override func indexPathsToDeleteForSupplementaryView(ofKind elementKind: String) -> [IndexPath] {
        return supplementaryViewsHandler.deleted(for: elementKind)
    }
}

Diffing and updating

Collor provides some features to easily update your collectionData.

Updating

Just append or remove cells or sections using CollectionData.update(_:) method. This means an end to fiddling around with IndexPath:

let newCellDescriptor = NewCellDescriptor(...)
let result = collectionData.update { updater in
    updater.append(cells: [newCellDescriptor], after: anotherCellDescriptor)
}
collectionView.performUpdates(with: result)

Here is the list of all update methods available:

  • append(cells:after:)
  • append(cells:before:)
  • append(cells:in:)
  • remove(cells:)
  • reload(cells:)
  • append(sections:after:)
  • append(sections:before:)
  • append(sections:)
  • remove(sections:)
  • reload(sections:)
Diffing

Collor is using a home made algorithm for getting the "diff" between two updates of your collectionData.

  • Diffing some sections:
sectionDescriptor.isExpanded = !sectionDescriptor.isExpanded
let result = collectionData.update{ updater in
    updater.diff(sections: [sectionDescriptor])
}
collectionView.performUpdates(with: result)
  • Diffing entire data
model.someUpdates()
let result = collectionData.update { updater in
    collectionData.reload(model: model)
    updater.diff()
}
collectionView.performUpdates(with: result)
  • Effortless management of decoration views

With DecorationViewHandler, you no longer need to implement code to manage your decoration views:

// register decoration view or class:
decorationViewHandler.register(viewClass: SimpleDecorationView.self, for: sectionBackgroundKind)
// caching
decorationViewHandler.add(attributes: backgroundAttributes)
// compute elements in rect
decorationViewHandler.attributes(in:rect)
// retrieving
decorationViewHandler.attributes(for: elementKind, at: atIndexPath)
// update handling
decorationViewHandler.prepare(forCollectionViewUpdates: updateItems)
return decorationViewHandler.inserted(for: elementKind)
return decorationViewHandler.deleted(for: elementKind)

Collor Realtime Sample

For more information, have a look at this medium article.

XCTemplates

Collor is published with 3 xctemplates for helping you creating ViewController, SectionDescriptor and CellDescriptor.

To install them, just go in xctemplates directory and run this command in a terminal:

sh install.sh

XCTemplates

Requirements

  • iOS 10.0+
  • Swift 4.2+ (get the 1.0.3 release for swift3.x, 1.1.23 for swift4.0)
  • Xcode 10.1+

Installation

CocoaPods

Collor is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod "Collor"

Carthage

Collor doesn't yet support Carthage. Work in progress...

Documentation

Documentation

Work in progress... 1% documented

Credits

Collor is owned and maintained by oui.sncf.

Collor was originally created by Gwenn Guihal.

License

Collor is available under the BSD license. See the LICENSE file for more info.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].