Framework to help you better manage UITableViews

Overview

Build Status Pods Version


UITableView made simple ๐Ÿ™Œ

Main Features
๐Ÿ™‰ Skip the UITableViewDataSource & UITableViewDelegate boilerplate and get right to building your UITableView!
๐ŸŒ€ Closure based API for section and row configuration
๐Ÿ“„ Built-in paging functionality
โœ… Unit Tested
๐Ÿค Written in Swift 4.2

OKTableViewLiaison is ๐Ÿ”จ with โค๏ธ by ๐Ÿ“ฑ @ OkCupid. We use the latest and greatest open source version of master in the OkCupid app.

Requirements

  • Xcode 10.0+
  • iOS 9.0+

Installation

CocoaPods

The preferred installation method is with CocoaPods. Add the following to your Podfile:

pod 'OKTableViewLiaison'

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Usage

OKTableViewLiaison allows you to more easily populate and manipulate UITableView rows and sections.

Getting Started

To get started, all you need to do is liaise an instance of UITableView to with a OKTableViewLiaison:

let liaison = OKTableViewLiaison()
let tableView = UITableView()

liaison.liaise(tableView: tableView)

By liaising your tableView with the liaison, the liaison becomes its UITableViewDataSource, UITableViewDelegate, and UITableViewDataSourcePrefetching. In the event you would like to remove the tableView from the liaison, simply invoke liaison.detach().

OKTableViewLiaison populates sections and rows using two main types:

Section

struct OKTableViewSection

To create a section for our tableView, create an instance of OKTableViewSection and add it to the liaison.

let section = OKTableViewSection()

let liaison = OKTableViewLiaison(sections: [section])

or

let section = OKTableViewSection()

liaison.append(section: section)

Supplementary Section Views

To notify the liaison that your OKTableViewSection will display a header and/or footer view, you must provide an instance of OKTableViewSectionComponentDisplayOption during initialization.

OKTableViewSectionComponentDisplayOption is an enumeration that notfies the liaison which supplementary views should be displayed for a given section. A header/footer view is represented by:

class OKTableViewSectionComponent<View: UITableViewHeaderFooterView, Model>

let header = OKTableViewSectionComponent<UITableViewHeaderFooterView, User>(.dylan)
let section = OKTableViewSection(componentDisplayOption: .header(component: header))

You can set a static height of a section component by using either a CGFloat value or closure:

header.set(height: .height, 55)

header.set(height: .height) { user -> CGFloat in
    return user.username == "dylan" ? 100 : 75
}

header.set(height: .estimatedHeight, 125)

In the event a height is not provided for a section component, the liaison will assume the supplementary view is self sizing and return a .height of UITableView.automaticDimension. Make sure you provide an .estimatedHeight to avoid layout complications.

The OKTableViewSectionComponent views can be customized using func set(command: OKTableViewSectionComponentCommand, with closure: @escaping (View, Model, Int) -> Void) at all the following lifecycle events:

  • configuration
  • didEndDisplaying
  • willDisplay
header.set(command: .configuration) { view, user, section in
    view.textLabel?.text = user.username
}

header.set(command: .willDisplay) { view, user, section in
    print("Header: \(view) will display for Section: \(section) with User: \(user)")
}

Rows

class OKTableViewRow<Cell: UITableViewCell, Model>

To add a row for a section, create an instance of OKTableViewRow and pass it to the initializer for a OKTableViewSection or if the row is added after instantiation you can perform that action via the liaison:

let row = OKTableViewRow<RowTableViewCell, RowModel>(model: RowModel(type: .small))
let section = OKTableViewSection(rows: [row])
liaison.append(section: section)

or

let row = OKTableViewRow<RowTableViewCell, RowModel>(model: RowModel(type: .small))
let section = OKTableViewSection()
liaison.append(section: section)
liaison.append(row: row)

OKTableViewRow heights are similarly configured to OKTableViewSection:

row.set(height: .height, 300)

row.set(height: .estimatedHeight, 210)

row.set(height: .height) { model -> CGFloat in
	switch model.type {
	case .large:
		return 400
	case .medium:
		return 200
	case .small:
		return 50
	}
}

In the event a height is not provided, the liaison will assume the cell is self sizing and return UITableView.automaticDimension.

The OKTableViewRow can be customized using func set(command: OKTableViewRowCommand, with closure: @escaping (Cell, Model, IndexPath) -> Void) at all the following lifecycle events:

  • accessoryButtonTapped
  • configuration
  • delete
  • didDeselect
  • didEndDisplaying
  • didEndEditing
  • didHighlight
  • didSelect
  • didUnhighlight
  • insert
  • move
  • reload
  • willBeginEditing
  • willDeselect
  • willDisplay
  • willSelect
row.set(command: .configuration) { cell, model, indexPath in
	cell.label.text = model.text
	cell.label.font = .systemFont(ofSize: 13)
	cell.contentView.backgroundColor = .blue
	cell.selectionStyle = .none
}

row.set(command: .didSelect) { cell, model, indexPath in
	print("Cell: \(cell) selected at IndexPath: \(indexPath)")
}

OKTableViewRow can also utilize UITableViewDataSourcePrefetching by using func set(prefetchCommand: OKTableViewPrefetchCommand, with closure: @escaping (Model, IndexPath) -> Void)

row.set(prefetchCommand: .prefetch) { model, indexPath in
	model.downloadImage()
}

row.set(prefetchCommand: .cancel) { model, indexPath in
    model.cancelImageDownload()
}

Cell/View Registration

OKTableViewLiaison handles cell & view registration for UITableView view reuse on your behalf utilizing your sections/rows OKTableViewRegistrationType<T>.

OKTableViewRegistrationType tells the liaison whether your reusable view should be registered via a Nib or Class.

By default, OKTableViewRow is instantiated with OKTableViewRegistrationType<Cell>.defaultClassType.

OKTableViewSection supplementary view registration is encapsulated by itsOKTableViewSectionComponentDisplayOption. By default, OKTableViewSection componentDisplayOption is instantiated with .none.

Pagination

OKTableViewLiaison comes equipped to handle your pagination needs. To configure the liaison for pagination, simply set its paginationDelegate to an instance of OKTableViewLiaisonPaginationDelegate.

OKTableViewLiaisonPaginationDelegate declares three methods:

func isPaginationEnabled() -> Bool, notifies the liaison if it should show the pagination spinner when the user scrolls past the last cell.

func paginationStarted(indexPath: IndexPath), passes through the indexPath of the last OKTableViewRow managed by the liaison.

func paginationEnded(indexPath: IndexPath), passes the indexPath of the first new OKTableViewRow appended by the liaison.

To update the liaisons results during pagination, simply use append(sections: [OKAnyTableViewSection]) or func append(rows: [OKAnyTableViewRow]) and the liaison will automatically handle the removal of the pagination spinner.

To use a custom pagination spinner, you can pass an instance OKAnyTableViewRow during the initialization of your OKTableViewLiaison. By default it uses OKPaginationTableViewRow provided by the framework.

Tips & Tricks

Because OKTableViewSection and OKTableViewRow utilize generic types and manage view/cell type registration, instantiating multiple different configurations of sections and rows can get verbose. Creating a subclass or utilizing a factory to create your various OKTableViewRow/OKTableViewSectionComponent types may be useful.

final class TextTableViewRow: OKTableViewRow<PostTextTableViewCell, String> {
	init(text: String) {
		super.init(text,
		registrationType: .defaultNibType)
	}
}
static func imageRow(with image: UIImage) -> AnyTableViewRow {
	let row = OKTableViewRow<ImageTableViewCell, UIImage>(image)

	row.set(height: .height, 225)

	row.set(command: .configuration) { cell, image, indexPath in
		cell.contentImageView.image = image
		cell.contentImageView.contentMode = .scaleAspectFill
	}

	return row
}

Contribution

OKTableViewLiaison is a framework in its infancy. It's implementation is not perfect. Not all UITableView functionality has been liaised just yet. If you would like to help bring OKTableViewLiaison to a better place, feel free to make a pull request.

Authors

โœŒ๏ธ Dylan Shine, [email protected]

License

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

Comments
  • 3.0.0

    3.0.0

    OKTableViewRegistrationType: Now wraps generic type T instead of T: UIView. Associated and computed identifier value/property renamed to reuseIdentifier

    OKTableViewSectionComponentDisplayOption: Removed internal func registerComponentViews(with tableView: UITableView)

    UITableView: Added generic helper functions for registering and dequeuing UITableViewCell & UITableViewHeaderFooterView

    OKTableViewLiaison: Removed public func section(for index: Int) -> OKTableViewSection? & public func section(for indexPath: IndexPath) -> OKTableViewSection? Removed func row(for indexPath: IndexPath) -> OKAnyTableViewRow? from public interface

    OKTableViewLiaison+Pagination: var lastIndexPath: IndexPath? is now private property on extension isShowingPaginationSpinner has been removed, now only uses waitingForPaginatedResults to determine if pagination is in progress. Implemented private func addPaginationSection() to handle adding Pagination Section. func endPagination(rows: [OKAnyTableViewRow]) and func endPagination(sections: [OKTableViewSection]) now support animation

    OKTableViewLiaison+Registration: UITableViewCell & UITableViewHeaderFooterView registration has been moved off the OKTableViewSection and onto the OKTableViewLiaison itself. Implemented func register(section: OKTableViewSection), func register(sections: [OKTableViewSection]), func register(row: OKAnyTableViewRow), and func register(rows: [OKAnyTableViewRow])

    OKTableViewContent: New protocol to encapsulate height, estimatedHeight, reuseIdentifier, and func register(with tableView: UITableView) for OKAnyTableViewRow & OKAnyTableViewSectionComponent

    OKTableViewLiaisonPaginationDelegate: Now conforms to AnyObject instead of class

    OKTableViewSection: OKTableViewSection is now a struct. Changes across the framework have been made to accomodate for this change, especially around array access when manipulating rows within a section.

    opened by dylanshine 0
  • 2.2.0

    2.2.0

    Changed OKTableViewRegistrationType to have generic type <T: UIView>. Updated API to simplify registering views for their default cases. Updated unit tests and README

    opened by dylanshine 0
  • 2.1.0

    2.1.0

    Make Section registrationTypes private and model property public Make Row registration types private and immutable Rename detachTableView to detach Update Unit Test Suite

    opened by dylanshine 0
  • 1.3.0

    1.3.0

    Refactor Example Make default height for non displayed section supplementary views CGFloat.leastNormalMagnitude Implement OKTableViewRegistrationType factory functions for OKTableViewRow & OKTableViewSection

    opened by dylanshine 0
  • 1.1.1

    1.1.1

    Changes to file structure Fixed pagination delegate unit tests affected by background threads Implemented row commands to correctly execute Updated unit tests

    enhancement 
    opened by dylanshine 0
  • 1.1.0

    1.1.0

    Changed closures to be @escaping instead of optional Added remove height functionality Implement move command to fire correctly Created Protocols folder and moved OKTableViewLiaisonPaginationDelegate into separate file Updated pod for example project

    opened by dylanshine 0
Releases(3.1.0)
  • 3.1.0(Sep 20, 2018)

  • 3.0.0(Sep 5, 2018)

    CHANGELOG:

    SECOND MAJOR RELEASE

    OKTableViewSection: OKTableViewSection is now a struct. Changes across the framework have been made to accomodate for this, particularly around Array access when manipulating rows within a section.

    OKTableViewRegistrationType: Now wraps generic type T instead of T: UIView. Associated and computed identifier value/property renamed to reuseIdentifier

    OKTableViewLiaison: Removed public func section(for index: Int) -> OKTableViewSection?, public func section(for indexPath: IndexPath) -> OKTableViewSection? and public func row(for indexPath: IndexPath) -> OKAnyTableViewRow?

    OKTableViewLiaison+Pagination: func endPagination(rows: [OKAnyTableViewRow]) and func endPagination(sections: [OKTableViewSection]) now support UITableViewRowAnimation

    OKTableViewLiaison+Registration: UITableViewCell & UITableViewHeaderFooterView registration has been moved off the OKTableViewSection and onto the OKTableViewLiaison itself.

    OKTableViewContent: New protocol to encapsulate height, estimatedHeight, reuseIdentifier, and func register(with tableView: UITableView) for OKAnyTableViewRow & OKAnyTableViewSectionComponent

    OKTableViewLiaisonPaginationDelegate: Now conforms to AnyObject instead of class

    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Aug 27, 2018)

    CHANGELOG:

    OKTableViewLiaison new functionality: public func section(for index: Int) -> OKTableViewSection? public func swapSection(at source: Int, with destination: Int, animation: UITableViewRowAnimation = .automatic, animated: Bool = true) public func reloadRow(at indexPath: IndexPath, with animation: UITableViewRowAnimation = .automatic)

    OKTableViewLiaison changes: public func swapRow(at source: IndexPath, with destination: IndexPath, animation: UITableViewRowAnimation = .automatic, animated: Bool = true) argument names changed (from: to:) -> (at: with:) func performTableViewUpdates(animated: Bool, _ closure: () -> Void), no longer has default animated parameter.

    OKTableViewSection changes: public let componentDisplayOption: OKTableViewSectionComponentDisplayOption, was private.

    OKTableViewSectionComponentDisplayOption changes: public var header: OKAnyTableViewSectionComponent? & public var footer: OKAnyTableViewSectionComponent?, were internal.

    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Aug 17, 2018)

    CHANGELOG:

    OKTableViewRegistrationType has been updated to OKTableViewRegistrationType<T: UIView> to simplify default registration cases.

    public static func defaultClassRegistration<T: UIView>(for view: T.Type) -> OKTableViewRegistrationType changed to public static var defaultClassType: OKTableViewRegistrationType

    public static func defaultNibRegistration<T: UIView>(for view: T.Type) -> OKTableViewRegistrationType changed to public static var defaultNibType: OKTableViewRegistrationType

    Unit Tests Updated README Updated

    Source code(tar.gz)
    Source code(zip)
  • 2.1.3(Jun 19, 2018)

  • 2.1.2(Jun 12, 2018)

    Fix bug related to type registration not occurring for sections that were already appended to the liaison prior to liaise being called. Added unit tests

    Source code(tar.gz)
    Source code(zip)
  • 2.1.1(Jun 11, 2018)

  • 2.1.0(Jun 5, 2018)

  • 2.0.0(May 31, 2018)

    First MAJOR update to the OKTableViewLiaison! CHANGE LOG:

    OKTableViewSection<Header: UITableViewHeaderFooterView, Footer: UITableViewHeaderFooterView, Model> has changed to simply OKTableViewSection.

    OKTableViewSectionSupplementaryViewDisplayOption has changed to OKTableViewSectionComponentDisplayOption, and now holds OKTableViewSectionComponent<View: UITableViewHeaderFooterView, Model> as associated values.

    OKTableViewSectionComponent<View: UITableViewHeaderFooterView, Model>, is similar to OKTableViewRow<Cell: UITableViewCell, Model>. It's the type used to create/configure header/footer views for your sections.

    Estimated Height configuration has been added for UITableViewHeaderFooterView. OKPlainTableViewSection has been removed.

    OKTableViewLiaison implements a new insert(sections: [OKTableViewSection], startingAt index: Int) function.

    Source code(tar.gz)
    Source code(zip)
  • 1.4.0(May 24, 2018)

    Implement UITableViewDataSourcePrefetching support for OKTableViewRows Refactor OKTableViewRow cell registration to fix bug during pagination Genereal gardening & refactoring Unit Tests

    Source code(tar.gz)
    Source code(zip)
  • 1.3.0(May 16, 2018)

    Refactor Example Make default height for non displayed section supplementary views CGFloat.leastNormalMagnitude Implement OKTableViewRegistrationType factory functions for OKTableViewRow & OKTableViewSection

    Source code(tar.gz)
    Source code(zip)
  • 1.2.3(May 10, 2018)

    Simplify supplementary view type registration logic for Sections Make section/row for IndexPath functions public Small changes to test suite

    Source code(tar.gz)
    Source code(zip)
  • 1.2.2(May 4, 2018)

  • 1.2.1(May 3, 2018)

  • 1.2.0(May 3, 2018)

    Updated example to use open source images Added User model to example Added ability to initialize OKTableViewLiaison with sections Updated unit tests

    Source code(tar.gz)
    Source code(zip)
  • 1.1.1(Apr 30, 2018)

  • 1.1.0(Apr 24, 2018)

    CHANGELOG: You can no longer pass optional closures when configuring a command. Functionality has been implemented to remove height commands for sections/rows.

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Apr 17, 2018)

Owner
null
APDynamicGrid is a SwiftUI package that helps you create consistent and animatable grids.

APDynamicGrid Overview APDynamicGrid is a SwiftUI package that helps you create consistent and animatable grids. The DynamicGrid View preserves the sa

Antonio Pantaleo 29 Jul 4, 2022
a TableView have thumbnail cell only, and you can use gesture let it expands other expansionView, all diy

ZYThumbnailTableView #####ๅฏๅฑ•ๅผ€ๅž‹้ข„่งˆTableView๏ผŒๅผ€ๆ”พๆŽฅๅฃ๏ผŒๅฎŒๅ…จ่‡ช็”ฑๅฎšๅˆถ #####An expandable preview TableView, custom-made all the modules completely with open API you c

null 950 Oct 17, 2022
Settings screen composing framework

THIS PROJECT IS NO LONGER MAINTAINED. HERE ARE SOME SUITABLE ALTERNATIVES: SwiftUI Form https://github.com/xmartlabs/Eureka https://github.com/neoneye

David Roman 1.3k Dec 25, 2022
Framework to help you better manage UITableViews

UITableView made simple ?? Main Features ?? Skip the UITableViewDataSource & UITableViewDelegate boilerplate and get right to building your UITableVie

null 84 Feb 4, 2022
CareKit is an open source software framework for creating apps that help people better understand and manage their health.

CareKit CareKitโ„ข is an open source software framework for creating apps that help people better understand and manage their health. The framework prov

CareKit 2.3k Dec 27, 2022
A fitness application using swift which can help user to hold a better sleep

Natcap - Good for your sleep This is a fitness application which can help user to hold a better sleep which depends on their previous sleeping habit.

Mill 0 Dec 13, 2021
A platform where NYUAD students can both Help and Seek Help.

A platform where NYUAD students can both Help and Seek Help.

Omar Rayyan 0 Nov 7, 2021
A guard to help you check if you make UI changes not in main thread

ODUIThreadGuard ODUIThreadGuard is a guard to help check if you make UI changes not in main thread. As Xcode 9 embedded this function into Xcode, ther

Old Donkey 690 Nov 23, 2022
Example project guide you schedules multiple thread for network requests in RxSwift, which is optimize your app's performance better.

RxSwift-Multi-Threading-Example Example project guide you schedules multiple thread for network requests in RxSwift, which is optimize your app's perf

Huy Trinh Duc 6 Nov 4, 2022
Headline News Widget for Better Touch Tool. You can display the articles fetched by rss.

BTTPluginHeadLineNews This is a headline news widget plugin for BTT(Better Touch Tool) You can display the articles fetched by rss. (Pock version is h

null 4 Jul 23, 2022
SuggestionsBox helps you build better a product trough your user suggestions. Written in Swift. ๐Ÿ—ณ

SuggestionsBox An iOS library to aggregate users feedback about suggestions, features or comments in order to help you build a better product. Swift V

Manuel Escrig 100 Feb 6, 2022
A drop-in universal library helps you to manage the navigation bar styles and makes transition animations smooth between different navigation bar styles

A drop-in universal library helps you to manage the navigation bar styles and makes transition animations smooth between different navigation bar styles while pushing or popping a view controller for all orientations. And you don't need to write any line of code for it, it all happens automatically.

Zhouqi Mo 3.3k Dec 21, 2022
Switshot is a game media manager helps you transfer your game media from Nintendo Switch to your phone, and manage your media just few taps.

Switshot is a game media manager helps you transfer your game media from Nintendo Switch to your phone, and manage your media just few taps.

Astrian Zheng 55 Jun 28, 2022
A drop-in universal library helps you to manage the navigation bar styles and makes transition animations smooth between different navigation bar styles

A drop-in universal library helps you to manage the navigation bar styles and makes transition animations smooth between different navigation bar styles while pushing or popping a view controller for all orientations. And you don't need to write any line of code for it, it all happens automatically.

Zhouqi Mo 3.3k Dec 21, 2022
A guy that helps you manage collections and placeholders in easy way.

Why? As mobile developers we all have to handle displaying collections of data. But is it always as simple as it sounds? Looks like spaghetti? It is a

AppUnite Sp. z o.o. Spk. 47 Nov 19, 2021
This is how you can manage and share logs in iOS application.

Logging in Swift In this example, you can find how to print all the logs effciently in iOS application. Along with, you will find how to share logs fo

Nitin Aggarwal 8 Mar 1, 2022
CheatyXML is a Swift framework designed to manage XML easily

CheatyXML CheatyXML is a Swift framework designed to manage XML easily. Requirements iOS 8.0 or later tvOS 9.0 or later Installation Cocoapods If you'

Louis Bodart 24 Mar 31, 2022
Powerful autolayout framework, that can manage UIView(NSView), CALayer and not rendered views. Not Apple Autolayout wrapper. Provides placeholders. Linux support.

CGLayout Powerful autolayout framework, that can manage UIView(NSView), CALayer and not rendered views. Has cross-hierarchy coordinate space. Implemen

Koryttsev Denis 45 Jun 28, 2022
AZPeerToPeerConnectivity is a wrapper on top of Apple iOS Multipeer Connectivity framework. It provides an easier way to create and manage sessions. Easy to integrate

AZPeerToPeerConnection Controller Features Multipeer Connectivity Connection via Bluetooth or Wifi No need write all session, browser, services delega

Afroz Zaheer 66 Dec 19, 2022