All Projects → traderepublic → SectionKit

traderepublic / SectionKit

Licence: MIT License
♻️ Reusable sections for UICollectionView

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to SectionKit

Alignedcollectionviewflowlayout
A collection view layout that gives you control over the horizontal and vertical alignment of the cells.
Stars: ✭ 751 (+1497.87%)
Mutual labels:  uicollectionview, uikit
Pagingkit
PagingKit provides customizable menu UI. It has more flexible layout and design than the other libraries.
Stars: ✭ 1,030 (+2091.49%)
Mutual labels:  uicollectionview, uikit
Viewanimator
ViewAnimator brings your UI to life with just one line
Stars: ✭ 6,592 (+13925.53%)
Mutual labels:  uicollectionview, uikit
Epoxy Ios
Epoxy is a suite of declarative UI APIs for building UIKit applications in Swift
Stars: ✭ 377 (+702.13%)
Mutual labels:  uicollectionview, uikit
Uicollectionviewsplitlayout
UICollectionViewSplitLayout makes collection view more responsive.
Stars: ✭ 226 (+380.85%)
Mutual labels:  uicollectionview, uikit
Uicollectionview Layouts Kit
📐 A set of custom layouts for UICollectionView with examples [Swift 5.3, iOS 12].
Stars: ✭ 410 (+772.34%)
Mutual labels:  uicollectionview, uikit
Collectionviewpaginglayout
a simple but highly customizable paging layout for UICollectionView.
Stars: ✭ 947 (+1914.89%)
Mutual labels:  uicollectionview, uikit
Verticalcardswiper
A marriage between the Shazam Discover UI and Tinder, built with UICollectionView in Swift.
Stars: ✭ 830 (+1665.96%)
Mutual labels:  uicollectionview, uikit
Collectionviewslantedlayout
A CollectionView Layout displaying a slanted cells
Stars: ✭ 2,029 (+4217.02%)
Mutual labels:  uicollectionview, uikit
Gskstretchyheaderview
A generic stretchy header for UITableView and UICollectionView
Stars: ✭ 1,624 (+3355.32%)
Mutual labels:  uicollectionview, uikit
Wlemptystate
WLEmptyState is an iOS based component that lets you customize the view when the dataset of a UITableView or a UICollectionView is empty. We created a sample project with the WLEmptyState component to show how you can use it.
Stars: ✭ 305 (+548.94%)
Mutual labels:  uicollectionview, uikit
UIComponent
Write UI in crazy speed, with great perf & no limitations.
Stars: ✭ 333 (+608.51%)
Mutual labels:  uicollectionview, uikit
TinderUISamples
[ING] - TinderのようなUIを様々な実装で実現してみる
Stars: ✭ 30 (-36.17%)
Mutual labels:  uicollectionview, uikit
Owl
A declarative type-safe framework for building fast and flexible lists with UITableViews & UICollectionViews
Stars: ✭ 423 (+800%)
Mutual labels:  uicollectionview, uikit
Basecomponents
BaseComponents aims to provide easily reusable and understandable components to increase productivity with UIKit and Foundation APIs
Stars: ✭ 92 (+95.74%)
Mutual labels:  uicollectionview, uikit
Squaremosaiclayout
An extandable mosaic UICollectionViewLayout with a focus on extremely flexible customizations 🔶
Stars: ✭ 243 (+417.02%)
Mutual labels:  uicollectionview, uikit
ios ui recipe showcase
iOSアプリ開発 - UI実装であると嬉しいレシピブック掲載サンプル
Stars: ✭ 54 (+14.89%)
Mutual labels:  uicollectionview, uikit
Generic-Network-Layer iOS
Generic Network Layer created using Swift.
Stars: ✭ 32 (-31.91%)
Mutual labels:  uikit
LSAdditions
The Category of Commonly used controls and you can create a control quickly(Object, Control ...)
Stars: ✭ 15 (-68.09%)
Mutual labels:  uikit
toast-swift
A Swift Toast view - iOS 14 style and newer - built with UIKit. 🍞
Stars: ✭ 85 (+80.85%)
Mutual labels:  uikit

SectionKit

Unit Tests SwiftPM compatible Carthage compatible Release

By using SectionKit each section in a UICollectionView is implemented separately, so you can keep your classes small and maintainable. Sections can be combined like building blocks and creating screens with otherwise complex datasources becomes manageable.

At Trade Republic we are using SectionKit extensively. It powers most of our screens, with some of them containing up to 30 different types of sections. By combining SectionKit with ReactiveSwift and a reactive network protocol we are able to provide truly dynamic experiences.

This library is inspired by IGListKit, but it is implemented in Swift and it offers a type safe API through the use of generics.

To see SectionKit in action please check out the example project.

Contents:

Installation

Swift Package Manager

Automatically in Xcode:

  • Click File > Swift Packages > Add Package Dependency...
  • Use the package URL https://github.com/traderepublic/SectionKit to add SectionKit/DiffingSectionKit to your project.

Manually in your Package.swift file:

On the package:

dependencies: [
    .package(name: "SectionKit", url: "https://github.com/traderepublic/SectionKit", from: "1.0.0")
]

On a target:

dependencies: [
    .product(name: "SectionKit", package: "SectionKit"),
    .product(name: "DiffingSectionKit", package: "SectionKit") // optionally, includes diffing via DifferenceKit
]

Carthage

Add this to your Cartfile:

github "traderepublic/SectionKit" ~> 1.0

Note: Since the xcframework variant of DifferenceKit is linked against, make sure to build Carthage dependencies using the --use-xcframeworks option. For more information please visit the Carthage repository.

Quick Start

To get started, we need to initialise a CollectionViewAdapter. That object handles the communication to and from the UICollectionView. Since we want to have multiple sections we'll use the ListCollectionViewAdapter, but if there would only be a single section we could also use the SingleSectionCollectionViewAdapter.

Code
import SectionKit

final class MyCollectionViewController: UIViewController {
    private var collectionViewAdapter: CollectionViewAdapter!

    private let collectionView = UICollectionView(
        frame: .zero, 
        collectionViewLayout: UICollectionViewFlowLayout()
    )

    override func loadView() {
        view = collectionView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionViewAdapter = ListCollectionViewAdapter(
            collectionView: collectionView,
            dataSource: self, // no worries, we're going to add conformance to the protocol in a bit
            viewController: self
        )
    }
}

In this example we're going to have two sections and we'll now define their respective models FirstSectionModel and SecondSectionModel:

Code
struct FirstSectionModel {
    let items = ["Hello", "world"]
}

struct SecondSectionModel {
    let item = "Single item"
}

The next thing we want to do is to implement their corresponding SectionController. In this example, the first section shows a list of strings and the second section shows a single string. For both cases there are base classes we can inherit from:

Code
class FirstSectionController: ListSectionController<FirstSectionModel, String> {
    override func items(for model: FirstSectionModel) -> [String] {
        model.items
    }

    override func cellForItem(at indexPath: SectionIndexPath, in context: CollectionViewContext) -> UICollectionViewCell {
        // cell types are automatically registered when dequeuing
        let cell = context.dequeueReusableCell(StringCell.self, for: indexPath)
        cell.label.text = items[indexPath]
        return cell
    }

    override func sizeForItem(at indexPath: SectionIndexPath, using layout: UICollectionViewLayout, in context: CollectionViewContext) -> CGSize {
        CGSize(width: context.containerSize.width, height: 50)
    }
}

class SecondSectionController: SingleItemSectionController<SecondSectionModel, String> {
    override func item(for model: SecondSectionModel) -> String? {
        model.item
    }

    override func cellForItem(at indexPath: SectionIndexPath, in context: CollectionViewContext) -> UICollectionViewCell {
        // cell types are automatically registered when dequeuing
        let cell = context.dequeueReusableCell(StringCell.self, for: indexPath)
        cell.label.text = item
        return cell
    }

    override func sizeForItem(at indexPath: SectionIndexPath, using layout: UICollectionViewLayout, in context: CollectionViewContext) -> CGSize {
        CGSize(width: context.containerSize.width, height: 50)
    }
}

At last we want to implement the ListCollectionViewAdapterDataSource protocol. Here we're providing the SectionController for each model.

The sections both need a unique identifier, so the underlying SectionController can be recycled, which is necessary for animating updates.

Please note: Although the identifier needs to be unique across the list of sections, it also needs to be persistent across updates so the previous SectionController can be reused.

Code
enum MyCollectionSectionId: Hashable {
    case first
    case second
}

protocol MyCollectionSection {
    var sectionId: MyCollectionSectionId { get }
}

extension FirstSectionModel: MyCollectionSection {
    var sectionId: MyCollectionSectionId { .first }
}

extension SecondSectionModel: MyCollectionSection {
    var sectionId: MyCollectionSectionId { .second }
}

extension MyCollectionViewController: ListCollectionViewAdapterDataSource {
    // this can be implemented in a viewmodel instead
    private func createSectionModels() -> [MyCollectionSection] {
        [FirstSectionModel(), SecondSectionModel()]
    }

    func sections(for adapter: CollectionViewAdapter) -> [Section] {
        createSectionModels().compactMap {
            switch $0 {
            case let model as FirstSectionModel:
                return Section(
                    id: model.sectionId,
                    model: model,
                    controller: FirstSectionController(model: model)
                )

            case let model as SecondSectionModel:
                return Section(
                    id: model.sectionId,
                    model: model,
                    controller: SecondSectionController(model: model)
                )

            default:
                assertionFailure("\(#function): unknown section model: \($0)")
                return nil
            }
        }
    }
}

That's it! Since both sections are completely decoupled from each other, they can be easily reused in other places in the app and writing unit tests becomes much easier!

As a final bonus, if you want animated updates, you can use the DiffingListSectionController (import DiffingSectionKit) instead of the "normal" ListSectionController. If you're running iOS 13+ you may also use the FoundationDiffingListSectionController that is already contained in the SectionKit module.

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].