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
A SwiftUI component to make handling of email links better.

EmailLink A SwiftUI component to make handling of email links better. Not only will EmailLink use the correct default client, it will also prompt the

Joe Scotto 16 Sep 24, 2022
Apple's SwiftUI Essentials Series. An iOS app that helps users manage their daily scrums.

Scrumdinger (Work in progress) Apple's SwiftUI Essentials Series An iOS app that helps users manage their daily scrums. To help keep scrums short and

VinΓ­cius Moreira 1 Feb 14, 2022
An app that will help UI/UX designers and iOS developpers to easily work together, using demos and examples about iOS capabilities, limitations, ecosystem, ...

Demoapp Work in progress... ?? What's about? It's an app built in SwiftUI that will help UI/UX designers and iOS developpers to work together smoothly

Kaww 2 Nov 2, 2022
Library to help handle mentions

SZMentions is no longer being updated, please use SZMentionsSwift SZMentions is a lightweight mentions library for iOS. This library was built to assi

Steven Zweier 11 Dec 24, 2021
Each step you take reveals a new horizon. You have taken the first step today.

The story Seeing the animations behind Paper, or the transitions behind Mail, being in a world of flat design and transitions, user interaction, app b

Ramon Gilabert 152 Nov 3, 2022
Design-system-demo - This example code is bare-bones to show you what this framework can do

Basic Style Dictionary This example code is bare-bones to show you what this fra

Tylen St Hilaire 0 Feb 3, 2022
Poi - You can use tinder UI like tableview method

Poi You can use tinder UI like tableview method Installation Manual Installation Use this command git clone [email protected]:HideakiTouhara/Poi.git Imp

null 65 Nov 7, 2022
Presentation helps you to make tutorials, release notes and animated pages.

Presentation helps you to make tutorials, release notes and animated pages.

HyperRedink 3k Dec 28, 2022
Letters animation allows you to click on different letters and accordingly it will animate letters in a cool way. It has a very attractive UI and is very easy to use.

Letters Animation Cool Letters Animation in iOS written in Swift. Preview Table of content :- Description How to add in your project Requirement Licen

MindInventory 31 Oct 4, 2022
Numbers animation allows you to click on different numbers and accordingly it will animate numbers in a cool way. It has a very attractive UI and is very easy to use.

Numbers Animation Cool Numbers Animation in iOS written in Swift. Preview Table of content :- Description How to add in your project Requirement Licen

MindInventory 31 Oct 4, 2022
Reading animation allows you to click on the different page numbers and accordingly it will animate page changes in a cool way. It has a very attractive UI and is very easy to use.

Reading Animation Cool Reading Animation in iOS written in Swift. Preview Table of content :- Description How to add in your project Requirement Licen

MindInventory 42 Oct 4, 2022
MotionBlur allows you to add motion blur effect to iOS animations.

MotionBlur MotionBlur allows you to add motion blur effect to your animations (currently only position's change). See the accompanying blog post to le

Arek Holko 1.5k Nov 3, 2022
UIImageView subclass that allows you to display a looped video and dynamically switch it.

AKVideoImageView Motivation AKVideoImageView was created because I wasn't satisfied with the standard AVPlayer when I was implementing a video backgro

Oleksandr Kirichenko 125 Apr 5, 2022
Various view's effects for iOS, written in Swift. Allows you to animate views nicely with easy to use extensions

Various view's effects for iOS, written in Swift. Allows you to animate views nicely with easy to use extensions. Every animation is randomized. Currently supported animations:

Artur Rymarz 23 Aug 23, 2022
jasu 29 Dec 20, 2022
Protoyping-Project WallAngle - With this App, you can measure the angle without searching for tools and calculations

Protoyping-Project_WallAngle This is the App that I made for the Prototyping Pro

null 1 Apr 4, 2022
ButtonClickStyle - This is a Customizable/Designable Button View, with 15 animated click styles, that allows you to design your own buttons from subviews, in storyboard and xib right away.

ButtonClickStyle - This is a Customizable/Designable Button View, with 15 animated click styles, that allows you to design your own buttons from subviews, in storyboard and xib right away.

Rustam 25 Oct 10, 2022
You can dismiss modal by using gesture

RPModalGestureTransition You can dismiss modal by using gesture. Usage 1.Define animation You define animator class inherits UIViewControllerAnimatedT

Naoya Sugimoto 90 Apr 21, 2020