#TableKit
TableKit is a super lightweight yet powerful generic library that allows you to build complex table views in a declarative type-safe manner.
It hides a complexity of UITableViewDataSource
and UITableViewDelegate
methods behind the scene, so your code will be look clean, easy to read and nice to maintain.
Features
- Type-safe generic cells
- Functional programming style friendly
- The easiest way to map your models or view models to cells
- Automatic cell registration*
- Correctly handles autolayout cells with multiline labels
- Chainable cell actions (select/deselect etc.)
- Support cells created from code, xib, or storyboard
- Support different cells height calculation strategies
- Support portrait and landscape orientations
- No need to subclass
- Extensibility
- Swift 3
Getting Started
An example app is included demonstrating TableKit's functionality.
Basic usage
Create your rows:
import TableKit
let row1 = TableRow<StringTableViewCell>(item: "1")
let row2 = TableRow<IntTableViewCell>(item: 2)
let row3 = TableRow<UserTableViewCell>(item: User(name: "John Doe", rating: 5))
Put rows into section:
let section = TableSection(rows: [row1, row2, row3])
And setup your table:
let tableDirector = TableDirector(tableView: tableView)
tableDirector += section
Done. Your table is ready. Your cells have to conform to ConfigurableCell
protocol:
class StringTableViewCell: UITableViewCell, ConfigurableCell {
func configure(with string: String) {
textLabel?.text = string
}
}
class UserTableViewCell: UITableViewCell, ConfigurableCell {
static var estimatedHeight: CGFloat? {
return 100
}
// is not required to be implemented
// by default reuse id is equal to cell's class name
static var reuseIdentifier: String {
return "my id"
}
func configure(with user: User) {
textLabel?.text = user.name
detailTextLabel?.text = "Rating: \(user.rating)"
}
}
You could have as many rows and sections as you need.
Row actions
It nice to have some actions that related to your cells:
let action = TableRowAction<StringTableViewCell>(.click) { (data) in
// you could access any useful information that relates to the action
// data.cell - StringTableViewCell?
// data.item - String
// data.indexPath - NSIndexPath
}
let row = TableRow<StringTableViewCell>(item: "some", actions: [action])
Or, using nice chaining approach:
let row = TableRow<StringTableViewCell>(item: "some")
.action(.click) { (data) in
}
.action(.shouldHighlight) { (data) -> Bool in
return false
}
You could find all available actions here.
Custom row actions
You are able to define your own actions:
struct MyActions {
static let ButtonClicked = "ButtonClicked"
}
class MyTableViewCell: UITableViewCell, ConfigurableCell {
@IBAction func myButtonClicked(sender: UIButton) {
TableCellAction(key: MyActions.ButtonClicked, sender: self).invoke()
}
}
And handle them accordingly:
let myAction = TableRowAction<MyTableViewCell>(.custom(MyActions.ButtonClicked)) { (data) in
}
Advanced
Cell height calculating strategy
By default TableKit relies on self-sizing cells. In that case you have to provide an estimated height for your cells:
class StringTableViewCell: UITableViewCell, ConfigurableCell {
// ...
static var estimatedHeight: CGFloat? {
return 255
}
}
It's enough for most cases. But you may be not happy with this. So you could use a prototype cell to calculate cells heights. To enable this feature simply use this property:
tableDirector.shouldUsePrototypeCellHeightCalculation = true
It does all dirty work with prototypes for you behind the scene, so you don't have to worry about anything except of your cell configuration:
class ImageTableViewCell: UITableViewCell, ConfigurableCell {
func configure(with url: NSURL) {
loadImageAsync(url: url, imageView: imageView)
}
override func layoutSubviews() {
super.layoutSubviews()
contentView.layoutIfNeeded()
multilineLabel.preferredMaxLayoutWidth = multilineLabel.bounds.size.width
}
}
You have to additionally set preferredMaxLayoutWidth
for all your multiline labels.
Functional programming
It's never been so easy to deal with table views.
let users = /* some users array */
let click = TableRowAction<UserTableViewCell>(.click) {
}
let rows: [Row] = users.filter({ $0.state == .active }).map({ TableRow<UserTableViewCell>(item: $0.name, actions: [click]) })
tableDirector += rows
Done, your table is ready.
Automatic cell registration
TableKit can register your cells in a table view automatically. In case if your reusable cell id mathces cell's xib name:
MyTableViewCell.swift
MyTableViewCell.xib
You can also turn off this behaviour:
let tableDirector = TableDirector(tableView: tableView, shouldUseAutomaticCellRegistration: false)
and register your cell manually.
Installation
CocoaPods
To integrate TableKit into your Xcode project using CocoaPods, specify it in your Podfile
:
pod 'TableKit'
Carthage
Add the line github "maxsokolov/tablekit"
to your Cartfile
.
Manual
Clone the repo and drag files from Sources
folder into your Xcode project.
Requirements
- iOS 8.0+
- Xcode 8.0+
License
TableKit is available under the MIT license. See LICENSE for details.