Reimagining UICollectionView

Overview

CollectionKit

Reimagining UICollectionView

A modern Swift framework for building composable data-driven collection view.

Carthage compatible Version License Build Status codecov Xcode 8.2+ iOS 8.0+ Swift 3.0+ Slack

Migration Guide

v2.0

Features

  • Rewritten UICollectionView on top of UIScrollView.
  • Automatically diff data changes and update UI.
  • Superb performance through cell reuse, batched reload, visible-only diff, & the use of swift value types.
  • Builtin layout & animation systems specifically built for collections.
  • Composable sections with independent layout.
  • Strong type checking powered by Swift Generics.

Install

# CocoaPods
pod "CollectionKit"

# Carthage
github "SoySauceLab/CollectionKit"

Getting Started

To start using CollectionKit, use CollectionView in place of UICollectionView. CollectionView is CollectionKit's alternative to UICollectionView. You give it a Provider object that tells CollectionView how to display a collection.

The simpliest way to construct a provider is by using BasicProvider class.

BasicProvider

To build a BasicProvider, here is what you need:

  • DataSource
    • an object that supplies data to the BasicProvider.
  • ViewSource
    • an object that maps each data into a view, and update the view accordingly
  • SizeSource
    • an function that gives the size for each cell.

It sounds complicated, but it really isn't. Here is a short example demostrating how it all works.

let dataSource = ArrayDataSource(data: [1, 2, 3, 4])
let viewSource = ClosureViewSource(viewUpdater: { (view: UILabel, data: Int, index: Int) in
  view.backgroundColor = .red
  view.text = "\(data)"
})
let sizeSource = { (index: Int, data: Int, collectionSize: CGSize) -> CGSize in
  return CGSize(width: 50, height: 50)
}
let provider = BasicProvider(
  dataSource: dataSource,
  viewSource: viewSource,
  sizeSource: sizeSource
)

//lastly assign this provider to the collectionView to display the content
collectionView.provider = provider

Note that we used ArrayDataSource & ClosureViewSource here. These two classes are built-in to CollectionKit, and should be able to serve most jobs. You can implement other dataSource and viewSource as well. Imagine implementing a NetworkDataSource in your project, that retrives json data and parse into swift objects.

Reload

It is easy to update the CollectionView with new data.

dataSource.data = [7, 8, 9]

This will trigger an update of the CollectionView that is served by this dataSource.

Note that append and other array mutating methods will also work.

dataSource.data.append(10)
dataSource.data.append(11)
dataSource.data.append(12)

We updated the array three times in this example. Each update is triggering a reload. You might be thinking that this is very computational intensive, but it isn't. CollectionKit is smart enough to only update once per layout cycle. It will wait until the next layout cycle to actually reload.

After executing the 3 lines above, CollectionView will still show [7, 8, 9]. But once the current run loop cycle is completed, CollectionView will update immediately. Your user won't notice any lag from this process.

To trigger an update immediately, you can call collectionView.reloadData() or provider.reloadData() or dataSource.reloadData().

To make collectionView reload on the next layout cycle, you can call collectionView.setNeedsReload() or provider.setNeedsReload() or dataSource.setNeedsReload(). You might already noticed, once you update the array inside ArrayDataSource, it is basically calling setNeedsReload() for you.

Note that if you assign an array to the dataSource and later update that array instead. It won't actually update the CollectionView

var a = [1, 2 ,3]
dataSource.data = a
a.append(5) // won't trigger an update be cause dataSource.data & a is now two different array.
a = [4 ,5 ,6] // also won't trigger an update

Layout

Up to this point, the collection is still a bit ugly to look at. Every cell is left aligned and doesn't have space in between. You might want the views to be evenly spaced out, or you might want to add some spacing in between items or lines.

These can be achieved with Layout objects. Here is an example.

provider.layout = FlowLayout(spacing: 10, justifyContent: .center)

FlowLayout is a Layout class that it built-in to CollectionKit. There are many more built-in layouts including WaterfallLayout & RowLayout. You can also easily create your own layout.

FlowLayout is basically a better UICollectionViewFlowLayout that aligns items in row by row fashion. It supports lineSpacing, interitemSpacing, alignContent, alignItems, & justifyContent.

Every layout also supports inset(by:) and transposed() methods.

inset(by:) adds an outer padding to the layout and return the result layout as InsetLayout.

let inset = UIEdgeInset(top: 10, left: 10, bottom: 10, right: 10)
provider.layout = FlowLayout(spacing: 10).inset(by: inset)

transposed() converts a vertical layout into a horizontal layout or vice-versa. It returns the original layout wrapped inside a TransposedLayout

provider.layout = FlowLayout(spacing: 10).transposed()

You can also use them together like

let inset = UIEdgeInset(top: 10, left: 10, bottom: 10, right: 10)
provider.layout = FlowLayout(spacing: 10).transposed().inset(by: inset)

There can be a lot to talk about with Layouts. We will create more tutorial later to teach you how to create your own layout and show you some advance usages. In the mean time, feel free to dive in the source code. I promise you it is not complecated at all.

Composing (ComposedProvider)

The best feature of CollectionKit, is that you can freely combine providers together into multiple sections within one CollectionView. And it is REALLY EASY to do so.

let finalProvider = ComposedProvider(sections: [provider1, provider2, provider3])

collectionView.provider = finalProvider

To update individual sections, just update its own dataSource.

provider2DataSource.data = [2]

You can also live update sections around.

finalProvider.sections = [provider2, provider3, provider1]

Or add more to it.

finalProvider.sections.append(provider4)

You can even put ComposedProvider into another ComposedProvider no problem.

let trulyFinalProvider = ComposedProvider(sections: [finalProvider, provider5])

collectionView.provider = trulyFinalProvider

How cool is that!

Animation

CollectionKit offers a animation system which allows you to create fancy animations and adjust how cells are displayed.

Here are some examples of custom animators that is included in the example project. They can be used in combination with any layout. Here we are using a transposed waterfall layout.

Wobble Edge Shrink Zoom

Animator can also perform animations when a cell is added/moved/deleted. Here is an example showing a 3d scale animation with a cascading effect.

It is easy to use an Animator. You can assign it to providers, cells, or to entire CollectionView.

// apply to the entire CollectionView
collectionView.animator = ScaleAnimator()

// apply to a single section, will override CollectionView's animator
provider.animator = FadeAnimator()

// apply to a single view, will take priority over all other animators
view.collectionAnimator = WobbleAnimator()

Note: that in order to use WobbleAnimator, you have to include pod "CollectionKit/WobbleAnimator" subspec to your podfile.

Please checkout the example project to see many of these examples in action.

Questions? Want to contribute?

Join our public Slack!

Comments
  • Reuse cells

    Reuse cells

    Hello! When user scroll every cell are creating again. My cells creating from xib, so it too expensive to create every cells again when scroll. Is there any built-in layout or something else, so my cells will reuse, not create again? Thanks!

    opened by Banck 20
  • Dynamic height in sizeProvider

    Dynamic height in sizeProvider

    I have a view that consists of a label for a title, a label for a subtitle and a textfield. Since I don't know of the lenght of title + subtitle, it is possible for them to have multiple lines. This is the view:

    ` import Foundation import UIKit

    class GenericSingleLineInputView: GenericView<String> {
    
    var viewModel: GenericSingleLineInputViewModel?
    
    private let title: UILabel = {
       let title = UILabel()
        title.font = Config.Font.text
        title.textColor = Config.Color.text
        title.backgroundColor = UIColor.red
        title.numberOfLines = 0
        return title
    }()
    
    private let subtitle: UILabel = {
        let title = UILabel()
        title.font = Config.Font.smallText
        title.textColor = Config.Color.text
        title.backgroundColor = UIColor.yellow
        title.numberOfLines = 0
        return title
    }()
    
    private let textfield: UITextField = {
       let textfield = UITextField()
        textfield.addTarget(self, action: #selector(inputValueChanged), for: .valueChanged)
        textfield.backgroundColor = UIColor.blue
        return textfield
    }()
    
    override func didLoad() {
        addSubview(title)
        addSubview(subtitle)
        addSubview(textfield)
        self.backgroundColor = UIColor.green
        title.snp.makeConstraints { (make) in
            make.top.equalTo(self).offset(12)
            make.left.equalTo(self)
            make.right.equalTo(self)
            make.bottom.equalTo(subtitle.snp.top)
        }
        
        subtitle.snp.makeConstraints { (make) in
            make.left.equalTo(self)
            make.right.equalTo(self)
            make.bottom.equalTo(textfield.snp.top)
        }
        
        textfield.snp.makeConstraints { (make) in
            make.height.equalTo(30)
            make.left.equalTo(self)
            make.right.equalTo(self)
            make.bottom.equalTo(self).offset(-12)
        }
    }
    
    @objc func inputValueChanged() {
        if let text = textfield.text {
            viewModel?.valueChanged(text)
        }
    }
    
    func setup(with viewModel: GenericSingleLineInputViewModel) {
        self.viewModel = viewModel
        title.text = viewModel.title
        subtitle.text = viewModel.subtitle
        textfield.text = viewModel.value
    }
    

    } `

    Now I know to implement the sizeProvider property to set the size. I've tried it that way:

    `
    let provider1 = CollectionProvider(dataProvider: CreateBudgetAddBudgetDataProvider(), viewProvider: CreateBudgetAddBudgetProvider())

        provider1.sizeProvider = {index, viewModel, size in
            let view = provider1.view(at: index)
            log.debug(view.sizeThatFits(CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude)))
            return CGSize(width: size.width, height: 100)
        }
    
        collectionView.provider = CollectionComposer(
            provider1
        )
    

    `

    However, this does not work, since let view = provider1.view(at: index) log.debug(view.sizeThatFits(CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude))) will always return zero.

    And this are the provider classes: ` class CreateBudgetAddBudgetProvider: CollectionViewProvider<BudgetViewModel, UIView> {

    override func update(view: UIView, data: BudgetViewModel, index: Int) {
        if let view = view as? GenericSingleLineInputView, let viewModel = data as? GenericSingleLineInputViewModel {
            view.setup(with: viewModel)
        }
    }
    
    override func view(data: BudgetViewModel, index: Int) -> UIView {
        let view: UIView
        
        if data is GenericSingleLineInputViewModel {
            view = reuseManager.dequeue(GenericSingleLineInputView())
        }
        else {
            view = UIView()
        }
        update(view: view, data: data, index: index)
        
        return view
    }
    

    }

    class CreateBudgetAddBudgetDataProvider: CollectionDataProvider { var data: [BudgetViewModel] = []

    override init() {
        super.init()
        data.append(GenericSingleLineInputViewModel(title: "Name",valueChanged: { (value) in
            
        }, subtitle: "Hier könne Ihr name stehen"))
    }
    
    override var numberOfItems: Int {
        get {
            return data.count
        }
    }
    
    override func data(at: Int) -> BudgetViewModel {
        return data[at]
    }
    

    } `

    edit: I'm sorry for the code formatting, can't get it to work 😅

    opened by bernhardwaidacher 10
  • Can't run the project

    Can't run the project

    Can you please explain in steps how to run the project using cocoapods or with direct download ?

    1.I download the project zip and open it 2.opened CollectionKit.xcodeproj 3.build "CollectionKit" 4. now what ?

    I'm objective-c developer and will be nice to run the samples in simple step. Thanks.

    opened by Asher1000 10
  • Remove and add animation doesn't work

    Remove and add animation doesn't work

    Hello! Don't understand why, but in your example when cell is adding or removing we can see the animation properly, but in my project removing the latest cell, even if I call removeFirst() :

    collectionView.provider = BasicProvider(
                dataSource: dataSource,
                viewSource: ClosureViewSource(viewGenerator: { (data, index) -> UILabel in
                    let cell = UILabel()
                    cell.text = data.name
                    cell.backgroundColor = .yellow
                    return cell
                }, viewUpdater: { (view: UILabel, data: Match, at: Int) in
                    view.text = data.name
                }),
                sizeSource: sizeSource,
                layout:  FlowLayout(lineSpacing: 10,justifyContent: .center),
                animator: WobbleAnimator(),
                tapHandler: { [weak self] context in
                    self?.dataSource.data.remove(at: context.index)
                }
            )
    
    

    Video: http://dropmefiles.com/KrXuP

    opened by Banck 9
  • Large Navbars

    Large Navbars

    Is the SizeProvider called for every data object in the Data Provider when the Collection View Size is changing? I have around 1300 items in my data and when using the Large Navigationbars the scrolling is seriously stuttering.

    I checked what the source of the stuttering might be and I found that the sizeProvider of every cell is called every time when the size of the collectionView changes. That might be the culprit.

    See the Example: 21zmub

    opened by Narsail 7
  • How to mix data/object types

    How to mix data/object types

    In a realistic case where the collection requires many different data/object types, how to implement this ? For example a settings page may require TextAndSwitchView, TextAndSliderView, LongTextView and so on..

    if there was something like... provider.viewClassForData = { dataObj in return dataObj.viewClass }

    opened by hiroshihorie 7
  • How could I set a select or tap style for cell or any interactionable style

    How could I set a select or tap style for cell or any interactionable style

    Thanks for the wonderful framework! How could I add any selection style?

    It seems to have no interaction style for select or tap. Even when I used a UIButton in my viewsource, it has no state change style interaction. How could I use it to enable the default button click interaction style?

    How could I make a background color or shadow change when I click the cell or any style change when I click a UIControl?

    opened by wakaryry 6
  • Convert the Convenience Inits to designated Inits to use them for subclassing.

    Convert the Convenience Inits to designated Inits to use them for subclassing.

    I tried to subclass the CollectionProvider today and got an error that I can't use the convenience Inits (like used in the documentation) for subclassing.

    My proposal is to convert the convenience inits to designated inits. Sadly simply removing the convenience mark resulted in an error:

    Designated initializer for cannot ... delegate (with 'self.init')
    

    I know that simply duplicating code isn't really helpful so if someone has a better solution to make those Inits subclassable, you'r welcome :)

    opened by Narsail 5
  • How can scroll to the selected item?(怎样才能滚动到所选项目)

    How can scroll to the selected item?(怎样才能滚动到所选项目)

    E.gscrollToRow(at indexPath: IndexPath, at scrollPosition: UITableView.ScrollPosition, animated: Bool) 例如scrollToRow(at indexPath: IndexPath, at scrollPosition: UITableView.ScrollPosition, animated: Bool)

    What should I do on CollectionKit? 我在CollectionKit上应该如何做?

    Thank you very much for this open source library! 非常感谢这个开源库!

    opened by wwdc14yh 4
  • Is pinterest (masonry) layout currently possible?

    Is pinterest (masonry) layout currently possible?

    Is pinterest style layout currently possible with CollectionKit?

    image

    Most of the examples I've seen have cells with the same height/position within each row.

    opened by sjmueller 4
  • No Prefetch? Scroll performance issues

    No Prefetch? Scroll performance issues

    Hi . First great work with CollectionKit . I Love it but I have huge performance issues with it. And noticed some strange things.

    There are no prefetch and no preload of views(cells) . running simple print() debug I can see that the views are created just as they become visible . That can't be right . That creates huge performance issues when scrolling . I need to be able to draw the view graphics before it enters the visibleframe.

    Looking at for example Texture by Facebook https://github.com/texturegroup/texture .. they preload not only one but 2-3 cells/views/nodes before becoming visible in order to get 60 fps scroll

    There are no control of how many view I would like to preload / prefetch

    I really really like this kit but I can't use it because of this ... and I really would not like to rewrite all of my code ...

    opened by agotfredsen 4
  • fix Crash detail:

    fix Crash detail:

    Fix: when CollectionView goto Reuse pool,need to set its provider = nil,otherwise there may be two collectionView have the same provider,and maybe will crash later. Fix:当CollectionView进入复用池,需要重置provider,避免出现 多个collectionView 持有同个provider对象,导致数据更新不同步,进而未同步的collectionView中flattenProvider的childSections范围错误导致越界崩溃

    opened by dishcool 0
  • Question?

    Question?

    Hi,

    I have a problem with the sourceSize implementation. What would be the best way to implement the display images from the url, knowing that each has a different size.

    let imagesProvider = BasicProvider(
                dataSource: dataSource,
                viewSource: ClosureViewSource(viewGenerator: { (data, index) -> UIImageView in
                    let view = UIImageView(image: UIImage(named:"pic_picture_placeholder"))    
                    view.layer.cornerRadius = 5
                    view.clipsToBounds = true
                                                
                    return view
                }, viewUpdater: { (view: UIImageView, data: JSON, at: Int) in
                            // ASync call
                            DataStoreImage.shared.load(data["url"].string, view) { image in
                                   ...
                                   view.image = image
                                   // how reload cell with resize ?
                            })
               },
               sourceSize: ??
    }
    

    Any suggestions?

    opened by Droppix 0
  • multi-view  cast view type error

    multi-view cast view type error

    // course view source
    let courseViewSource = ClosureViewSource { (view: StudyCar2CouseView, data: StudyCarCourseListModel, index: Int) in
                view.model = data
                   view.tapBtn = { model in
                       self.tapApplyCourse <= model
                   }
                }
    // coach view source
            let coachViewSource = ClosureViewSource { (view: StudyCar2CoachView, data: ClassCoachModel, index: Int) in
                view.model = data
                   view.tapBtn = { model in
                       self.tapApplyCoach <= model
                   }
                }
    // empty space view source
            let emptyViewSource = ClosureViewSource { (view: UIView, model: StudyCar2ApplyViewTypeProtocol, index: Int) in
                
            }
    
    // size provider
            let sizeSource = { (index: Int, viewType: StudyCar2ApplyViewTypeProtocol, collectionSize: CGSize) -> CGSize in
                if viewType is StudyCarCourseListModel || viewType is ClassCoachModel {
                    return CGSize(width: kScreenWid-30.fitR, height: 70.fitR)
                }
                return CGSize(width: 50, height: 50)
              }
    
    
            listView.provider = BasicProvider(dataSource: dataSource,
                                 viewSource: ComposedViewSource(viewSourceSelector: { (viewType) in
                                    if viewType is StudyCarCourseListModel {
                                            return courseViewSource
                                    }
                                    if viewType is ClassCoachModel {
                                        return coachViewSource
                                    }
                                    return emptyViewSource
                                }),
                                 sizeSource: sizeSource
            )
    

    when change data source

    occur cast view type error: Could not cast value of type 'StudyCar2CouseView' to 'StudyCar2CoachView'

    opened by SpectatorNan 0
  • build faild with error

    build faild with error

    'CollectionView' has different definitions in different modules; first difference is definition in module 'CollectionKit.Swift' found super class with type 'UIScrollView'

    opened by ShenYj 0
  • Using CollectionView Cell with IBOutlets built using XIB , crashes with nil

    Using CollectionView Cell with IBOutlets built using XIB , crashes with nil

    Below is the code am using

           let creatorProvider = BasicProvider(
                  dataSource: dataSource,
                  viewSource: ClosureViewSource(
                    viewGenerator: { (data, index) -> CreatorsCollectionViewCell in
                        return CreatorsCollectionViewCell.init()
                    },
                    viewUpdater: { (cell: CreatorsCollectionViewCell, data, index) in
                        cell.initData(user: data)
                  }),
                  sizeSource: { index, data, collectionSize in
                    // 2. return size for each StoryItemCell here
                    return CGSize(width: 64, height: 64)
                })
    
    opened by elemanhillary-zz 1
Releases(2.4.0)
  • 2.4.0(Apr 3, 2019)

  • 2.3.0(Dec 13, 2018)

    Changes

    • Add AutoLayoutSizeSource (#110) @Tylerian
    • cleanup simple view provider (#108)
    • Class based size source (#107)
    • Performance improvement with cell reuse (#100)
    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Sep 26, 2018)

  • 2.1.0(Sep 3, 2018)

    • fix issues caused by conflicting identifiers (#85) @Banck
    • change WaterfallLayout default parameters' values to align with other layouts
      • from init(columns: Int = 1, spacing: CGFloat = 10)
      • to init(columns: Int = 2, spacing: CGFloat = 0)
    • include WobbleAnimator into the podspec as a subspec.
      • pod "CollectionKit/WobbleAnimator"
    • BaseSimpleAnimator
      • rename BaseSimpleAnimator to SimpleAnimator to align with SimpleLayout
      • rename updateAnimationDuration to animationDuration
      • add var animationOptions: UIViewAnimationOptions
      • add var useSpringAnimation: Bool
      • add var springDamping: CGFloat
    • FadeAnimator
      • add var alpha: CGFloat
    • ScaleAnimator
      • change its superclass from BaseSimpleAnimator to FadeAnimator
      • add var scale: CGFloat

    Example project:

    • move examples into its own project. and switch from Carthage to Cocoapods.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Aug 8, 2018)

    • Fix unexpected UIScrollView behavior (#77) @humblehacker
    • ComposedHeaderProvider tapHandler index fix (#83) @Fabezi
    • Support tapHandler in SimpleViewProvider.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Jun 23, 2018)

  • 2.0.0(Jun 23, 2018)

    Focus of v2.0 will be towards API cleanliness & solves pain points with v1.0+

    Main feature of v2.0:

    1. Complete renaming of classes
      • With v1.0, naming of the classes weren't given enough thoughts. Names like CollectionProvider, ViewCollectionProvider, ViewProvider, DataProvider, etc.. are all quite confusing to use.
    2. Removing confusing initializer
    3. Sticky Header Support
    4. Initial support for mixed data type
    5. Layout cleanup
    6. Internal architectural & performance improvement

    Please checkout the migration guide for updating from v1~

    Source code(tar.gz)
    Source code(zip)
  • 1.3.1(Jun 22, 2018)

  • 1.3.0(Apr 12, 2018)

    • dequeue by Type (#39) @HiroshiHorie
    • Convert the Convenience Inits to designated Inits to use them for subclassing. (#47) @Narsail
    • Add in CollectionViewCollectionProvider. (#53) @jindulys
    • Add super designated initializer call to SpaceCollectionProvider. (#52) @jindulys
    • Scroll performance improvement
      • identifiers will now be cached and won't be used to calculate differences if there are no visible index change.
    • CollectionView.activeFrameInset is removed.
    • VisibleFrameInsetLayout is added to replace activeFrameInset.
      • To achieve the same effect as activeFrameInset, use:
      SomeLayout().insetVisibleFrame(by: activeFrameInset)
      
    • CollectionComposer reload performance is improved, especially for deeply nested sections. Previously each composer have to created an array of length of all items contained inside the composer during reload. and now it doesn't.
    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Dec 22, 2017)

    • Make CollectionViewProvider.reuseManager public: https://github.com/SoySauceLab/CollectionKit/commit/69c6f70b7dcfba68b465b2dbc7c462f9142a8463
    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Dec 14, 2017)

    There are quite a lot of improvements that went in 1.2.0.

    With this update, CollectionView will only query and diff identifiers for visible cells. This is a big performance gain. Previously it will ask the dataProvider for all identifiers when it reloads which takes O(n) time, n being to total number of cell. The only thing it does now that is O(n) time is doing the layout. But if your layout doesn't provide dynamic height, then you can write a layout that provide visible indexes in O(m) time, m being the number of cells visible on screen. This way you can build a CollectionView that diff and reloads in O(m) time no matter how big n is. At the moment I don't think it is possible with any other library. Any diffing library that work with UICollectionView will need to diff the whole set of data.

    CollectionProvider now has a viewGenerator parameter which allows you to configure a cell when the cell is first created. This function will only be called once per each cell and won't be called when the cell is reused. This helps shorten the viewUpdater parameter and provide better performance when reloading.

    ViewCollectionProvider now expose the views properties which allow you to configure views on the fly.

    ViewCollectionProvider now expose a sizeStrategyOverride dictionary properties which allow you to configure sizeStrategy for individual views.

    Source code(tar.gz)
    Source code(zip)
  • 1.0.3(Oct 19, 2017)

  • 1.0.2(Oct 18, 2017)

  • 1.0.1(Oct 17, 2017)

Owner
SoySauceLab
SoySauceLab
Automates prefetching of content in UITableView and UICollectionView

Automates preheating (prefetching) of content in UITableView and UICollectionView. Deprecated on iOS 10. This library is similar to UITableViewDataSou

Alexander Grebenyuk 633 Sep 16, 2022
UICollectionView layout for presenting of the overlapping cells.

StickyCollectionView UICollectionView layout for presenting of the overlapping cells. Objective-C version here Checkout demo Overview Installation Man

Bogdan Matveev 325 Oct 11, 2022
A data-driven UICollectionView framework for building fast and flexible lists.

A data-driven UICollectionView framework for building fast and flexible lists. Main Features ?? Never call performBatchUpdates(_:, completion:) or rel

Instagram 12.5k Jan 1, 2023
Netflix and App Store like UITableView with UICollectionView, written in pure Swift 4.2

GLTableCollectionView Branch Status master develop What it is GLTableCollectionView is a ready to use UITableViewController with a UICollectionView fo

Giulio 708 Nov 17, 2022
Incremental update tool to UITableView and UICollectionView

EditDistance is one of the incremental update tool for UITableView and UICollectionView. The followings show how this library update UI. They generate

Kazuhiro Hayashi 90 Jun 9, 2022
A generic small reusable components for data source implementation for UITableView/UICollectionView in Swift.

GenericDataSource A generic small reusable components for data source implementation for UITableView/UICollectionView written in Swift. Features Basic

null 132 Sep 8, 2021
Collapse and expand UICollectionView sections with one method call.

This library provides a custom UICollectionView that allows to expand and collapse sections. Provides a simple API to manage collection view appearanc

Touchlane 172 Dec 26, 2022
Conv smart represent UICollectionView data structure more than UIKit.

Conv Conv smart represent UICollectionView data structure more than UIKit. Easy definition for UICollectionView DataSource and Delegate methods. And C

bannzai 157 Nov 25, 2022
🚴 A declarative library for building component-based user interfaces in UITableView and UICollectionView.

A declarative library for building component-based user interfaces in UITableView and UICollectionView. Declarative Component-Based Non-Destructive Pr

Ryo Aoyama 1.2k Jan 5, 2023
ZHTCView - UITableview & UICollectionView

ZHTCView 这是一个使用Block替换代理的UITableview & UICollectionView。 使用方法如下: - (DSTableView *)tableView { if (!_tableView) { _tableView = DSTableView.

黑酒一 0 Jan 10, 2022
CollectionView - UICollectionView using UICollectionViewCompositionalLayout

CollectionView UICollectionView using UICollectionViewCompositionalLayout create

null 0 Jan 11, 2022
CollectionViewSegmentedControl - Scrollable UISegmentedControl built using a UICollectionView

CollectionViewSegmentedControl Installation CocoaPods Download CocoaPods Run 'Po

James Sedlacek 7 Nov 24, 2022
Protocol-oriented UICollectionView management, powered by generics and associated types.

DTCollectionViewManager Features Powerful mapping system between data models and cells, headers and footers Automatic datasource and interface synchro

Denys Telezhkin 308 Jan 6, 2023
Conv smart represent UICollectionView data structure more than UIKit.

Conv Conv smart represent UICollectionView data structure more than UIKit. Easy definition for UICollectionView DataSource and Delegate methods. And C

bannzai 155 May 12, 2022
A modest attempt to port UICollectionView to SwiftUI.

LazyCollectionView A modest attempt to port UICollectionView to SwiftUI. Table of Contents Description Requirements Installation Usage Components Impr

Unsplash 109 Dec 27, 2022
A marriage between the Shazam Discover UI and Tinder, built with UICollectionView in Swift.

VerticalCardSwiper A marriage between the Shazam Discover UI and Tinder, built with UICollectionView in Swift. Project goal and information The goal o

Joni Van Roost 1.2k Dec 28, 2022
Carbon🚴 A declarative library for building component-based user interfaces in UITableView and UICollectionView.

A declarative library for building component-based user interfaces in UITableView and UICollectionView. Declarative Component-Based Non-Destructive Pr

Ryo Aoyama 1.2k Jan 5, 2023
A UICollectionViewLayout subclass displays its items as rows of items similar to the App Store Feature tab without a nested UITableView/UICollectionView hack.

CollectionViewShelfLayout A UICollectionViewLayout subclass displays its items as rows of items similar to the App Store Feature tab without a nested

Pitiphong Phongpattranont 374 Oct 22, 2022
Gliding Collection is a smooth, flowing, customizable decision for a UICollectionView Swift Controller.

A smooth, flowing, customizable decision for a UICollectionView Swift Controller We specialize in the designing and coding of custo

Ramotion 1.5k Dec 19, 2022
🔄 GravitySlider is a beautiful alternative to the standard UICollectionView flow layout.

GravitySliderFlowLayout Made by Applikey Solutions Find this project on Dribbble Table of Contents Purpose Supported OS & SDK Versions Installation Us

Applikey Solutions 958 Dec 23, 2022