diff --git a/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift b/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift
index 6f5f7c4..ec505d6 100644
--- a/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift
+++ b/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift
@@ -19,13 +19,13 @@ class AutolayoutTableViewCell: UITableViewCell, ConfigurableCell {
@IBOutlet var titleLabel: UILabel!
@IBOutlet var subtitleLabel: UILabel!
+ static var estimatedHeight: CGFloat? {
+ return 500
+ }
+
func configure(with string: T) {
titleLabel.text = LoremIpsumTitle
subtitleLabel.text = LoremIpsumBody
}
-
- static func estimatedHeight() -> CGFloat? {
- return 500
- }
}
\ No newline at end of file
diff --git a/Demo/Classes/Presentation/Views/NibTableViewCell.swift b/Demo/Classes/Presentation/Views/NibTableViewCell.swift
index 74b4a27..d561314 100644
--- a/Demo/Classes/Presentation/Views/NibTableViewCell.swift
+++ b/Demo/Classes/Presentation/Views/NibTableViewCell.swift
@@ -13,11 +13,11 @@ class NibTableViewCell: UITableViewCell, ConfigurableCell {
@IBOutlet weak var titleLabel: UILabel!
+ static var defaultHeight: CGFloat? {
+ return 100
+ }
+
func configure(with number: Int) {
titleLabel.text = "\(number)"
}
-
- static func defaultHeight() -> CGFloat? {
- return 100
- }
}
\ No newline at end of file
diff --git a/README.md b/README.md
index f740cc1..c3adbf6 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-
+
@@ -12,12 +12,12 @@
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
+# Features
- [x] Type-safe generic cells
- [x] Functional programming style friendly
- [x] The easiest way to map your models or view models to cells
-- [x] Automatic cell registration
+- [x] Automatic cell registration*
- [x] Correctly handles autolayout cells with multiline labels
- [x] Chainable cell actions (select/deselect etc.)
- [x] Support cells created from code, xib, or storyboard
@@ -26,17 +26,19 @@ It hides a complexity of `UITableViewDataSource` and `UITableViewDelegate` metho
- [x] No need to subclass
- [x] Extensibility
-## Getting Started
+# Getting Started
An [example app](Demo) is included demonstrating TableKit's functionality.
-#### Basic usage
+## Basic usage
Create your rows:
```swift
+import TableKit
+
let row1 = TableRow(item: "1")
let row2 = TableRow(item: 2)
-let row3 = TableRow(item: 3.0)
+let row3 = TableRow(item: User(name: "John Doe", rating: 5))
```
Put rows into section:
```swift
@@ -47,24 +49,38 @@ And setup your table:
let tableDirector = TableDirector(tableView: tableView)
tableDirector += section
```
-Done. Your table is ready. You may want to look at your cell. It has to conform to `ConfigurableCell` protocol:
+Done. Your table is ready. Your cells have to conform to `ConfigurableCell` protocol:
```swift
class StringTableViewCell: UITableViewCell, ConfigurableCell {
- typealias T = String
+ func configure(with string: String) {
+
+ textLabel?.text = string
+ }
+}
- func configure(string: T, isPrototype: Bool) {
- titleLabel.text = string
+class UserTableViewCell: UITableViewCell, ConfigurableCell {
+
+ static var estimatedHeight: CGFloat? {
+ return 100
}
- static func estimatedHeight() -> CGFloat {
- return 44
+ // 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
+## Row actions
It nice to have some actions that related to your cells:
```swift
@@ -74,7 +90,7 @@ let action = TableRowAction(.click) { (data) in
// data.cell - StringTableViewCell?
// data.item - String
- // data.path - NSIndexPath
+ // data.indexPath - NSIndexPath
}
let row = TableRow(item: "some", actions: [action])
@@ -82,30 +98,54 @@ let row = TableRow(item: "some", actions: [action])
Or, using nice chaining approach:
```swift
let row = TableRow(item: "some")
- .action(TableRowAction(.click) { (data) in
+ .action(.click) { (data) in
- })
- .action(TableRowAction(.shouldHighlight) { (data) -> Bool in
+ }
+ .action(.shouldHighlight) { (data) -> Bool in
return false
- })
+ }
```
You could find all available actions [here](Sources/TableRowAction.swift).
-## Advanced
+## Custom row actions
-#### Cell height calculating strategy
+You are able to define your own actions:
+```swift
+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:
+```swift
+let myAction = TableRowAction(.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:
```swift
class StringTableViewCell: UITableViewCell, ConfigurableCell {
// ...
- static func estimatedHeight() -> CGFloat {
- return 44
+ 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 cell's heights. To enable this feature simply use this property:
+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:
```swift
tableDirector.shouldUsePrototypeCellHeightCalculation = true
```
@@ -113,11 +153,9 @@ It does all dirty work with prototypes for you [behind the scene](Sources/Height
```swift
class ImageTableViewCell: UITableViewCell, ConfigurableCell {
- func configure(url: NSURL, isPrototype: Bool) {
+ func configure(with url: NSURL) {
- if !isPrototype {
- loadImageAsync(url: url, imageView: imageView)
- }
+ loadImageAsync(url: url, imageView: imageView)
}
override func layoutSubviews() {
@@ -128,37 +166,55 @@ class ImageTableViewCell: UITableViewCell, ConfigurableCell {
}
}
```
-First of all you have to set `preferredMaxLayoutWidth` for all your multiline labels. And check if a configuring cell is a prototype cell. If it is, you don't have to do any additional work that not actually affect cell's height. For example you don't have to load remote image for a prototype cell.
+You have to additionally set `preferredMaxLayoutWidth` for all your multiline labels.
-#### Functional programming
+## Functional programming
It's never been so easy to deal with table views.
```swift
let users = /* some users array */
-let rows: [Row] = users.filter({ $0.state == .active }).map({ TableRow(item: $0.username) })
+let click = TableRowAction(.click) {
+
+}
+
+let rows: [Row] = users.filter({ $0.state == .active }).map({ TableRow(item: $0.name, actions: [click]) })
tableDirector += rows
```
-Done, your table is ready. It's just awesome!
+Done, your table is ready.
+## Automatic cell registration
-## Installation
+TableKit can register your cells in table view automatically. In case if your reusable cell id mathces cell's xib name:
-#### CocoaPods
+```ruby
+MyTableViewCell.swift
+MyTableViewCell.xib
+
+```
+You can also turn off this behaviour:
+```swift
+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`:
```ruby
pod 'TableKit'
```
-#### Carthage
+## Carthage
Add the line `github "maxsokolov/tablekit"` to your `Cartfile`.
-#### Manual
+## Manual
Clone the repo and drag files from `Sources` folder into your Xcode project.
-## Requirements
+# Requirements
- iOS 8.0+
- Xcode 7.0+
-## License
+# License
TableKit is available under the MIT license. See LICENSE for details.
\ No newline at end of file
diff --git a/Sources/ConfigurableCell.swift b/Sources/ConfigurableCell.swift
index 6c37e1f..18035ff 100644
--- a/Sources/ConfigurableCell.swift
+++ b/Sources/ConfigurableCell.swift
@@ -20,39 +20,36 @@
import UIKit
-public protocol ReusableCell {
-
- static func reusableIdentifier() -> String
- static func nib() -> UINib?
-}
+public protocol ConfigurableCell {
-public protocol ConfigurableCell: ReusableCell {
-
associatedtype T
-
- static func estimatedHeight() -> CGFloat?
- static func defaultHeight() -> CGFloat?
- func configure(with _: T)
-}
-public extension ReusableCell where Self: UITableViewCell {
-
- static func reusableIdentifier() -> String {
- return String(self)
- }
-
- static func nib() -> UINib? {
- return nil
- }
+ static var reuseIdentifier: String { get }
+ static var estimatedHeight: CGFloat? { get }
+ static var defaultHeight: CGFloat? { get }
+
+ func configure(with _: T)
}
public extension ConfigurableCell where Self: UITableViewCell {
- static func estimatedHeight() -> CGFloat? {
- return UITableViewAutomaticDimension
+ static var reuseIdentifier: String {
+ get {
+ return String(self)
+ }
+
}
- static func defaultHeight() -> CGFloat? {
- return nil
+ static var estimatedHeight: CGFloat? {
+ get {
+ return UITableViewAutomaticDimension
+ }
+
+ }
+
+ static var defaultHeight: CGFloat? {
+ get {
+ return nil
+ }
}
}
\ No newline at end of file
diff --git a/Sources/HeightStrategy.swift b/Sources/HeightStrategy.swift
index 7723bdd..66eec6f 100644
--- a/Sources/HeightStrategy.swift
+++ b/Sources/HeightStrategy.swift
@@ -49,7 +49,7 @@ public class PrototypeHeightStrategy: CellHeightCalculatable {
return height
}
- guard let cell = tableView.dequeueReusableCellWithIdentifier(row.reusableIdentifier) else { return 0 }
+ guard let cell = tableView.dequeueReusableCellWithIdentifier(row.reuseIdentifier) else { return 0 }
cell.bounds = CGRectMake(0, 0, tableView.bounds.size.width, cell.bounds.height)
diff --git a/Sources/TableCellManager.swift b/Sources/TableCellManager.swift
index 5cc29e8..891266e 100644
--- a/Sources/TableCellManager.swift
+++ b/Sources/TableCellManager.swift
@@ -20,25 +20,25 @@
import UIKit
-public class TableCellManager {
+class TableCellManager {
private var registeredIds = Set()
private weak var tableView: UITableView?
- public init(tableView: UITableView?) {
+ init(tableView: UITableView?) {
self.tableView = tableView
}
- public func register(cellType cellType: AnyClass, forReusableCellIdentifier reusableIdentifier: String) {
+ func register(cellType cellType: AnyClass, forCellReuseIdentifier reuseIdentifier: String) {
- if registeredIds.contains(reusableIdentifier) {
+ if registeredIds.contains(reuseIdentifier) {
return
}
// check if cell is already registered, probably cell has been registered by storyboard
- if tableView?.dequeueReusableCellWithIdentifier(reusableIdentifier) != nil {
+ if tableView?.dequeueReusableCellWithIdentifier(reuseIdentifier) != nil {
- registeredIds.insert(reusableIdentifier)
+ registeredIds.insert(reuseIdentifier)
return
}
@@ -46,13 +46,13 @@ public class TableCellManager {
// we hope that cell's xib file has name that equals to cell's class name
// in that case we could register nib
- if let _ = bundle.pathForResource(reusableIdentifier, ofType: "nib") {
- tableView?.registerNib(UINib(nibName: reusableIdentifier, bundle: bundle), forCellReuseIdentifier: reusableIdentifier)
+ if let _ = bundle.pathForResource(reuseIdentifier, ofType: "nib") {
+ tableView?.registerNib(UINib(nibName: reuseIdentifier, bundle: bundle), forCellReuseIdentifier: reuseIdentifier)
// otherwise, register cell class
} else {
- tableView?.registerClass(cellType, forCellReuseIdentifier: reusableIdentifier)
+ tableView?.registerClass(cellType, forCellReuseIdentifier: reuseIdentifier)
}
- registeredIds.insert(reusableIdentifier)
+ registeredIds.insert(reuseIdentifier)
}
}
\ No newline at end of file
diff --git a/Sources/TableDirector.swift b/Sources/TableDirector.swift
index 6794b24..ff6fd3f 100644
--- a/Sources/TableDirector.swift
+++ b/Sources/TableDirector.swift
@@ -123,9 +123,9 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate
let row = sections[indexPath.section].items[indexPath.row]
- cellManager?.register(cellType: row.cellType, forReusableCellIdentifier: row.reusableIdentifier)
+ cellManager?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier)
- let cell = tableView.dequeueReusableCellWithIdentifier(row.reusableIdentifier, forIndexPath: indexPath)
+ let cell = tableView.dequeueReusableCellWithIdentifier(row.reuseIdentifier, forIndexPath: indexPath)
if cell.frame.size.width != tableView.frame.size.width {
cell.frame = CGRectMake(0, 0, tableView.frame.size.width, cell.frame.size.height)
diff --git a/Sources/TableRow.swift b/Sources/TableRow.swift
index d4f56e3..b3cd9d1 100644
--- a/Sources/TableRow.swift
+++ b/Sources/TableRow.swift
@@ -38,7 +38,7 @@ public protocol RowHashable {
public protocol Row: RowConfigurable, RowActionable, RowHashable {
- var reusableIdentifier: String { get }
+ var reuseIdentifier: String { get }
var cellType: AnyClass { get }
var estimatedHeight: CGFloat? { get }
@@ -54,16 +54,16 @@ public class TableRow String {
- return TestTableViewCellOptions.ReusableIdentifier
- }
-
- static func estimatedHeight() -> Float {
+ static var estimatedHeight: CGFloat? {
return TestTableViewCellOptions.EstimatedHeight
}
+
+ static var reuseIdentifier: String {
+ return TestTableViewCellOptions.ReusableIdentifier
+ }
func configure(with item: T) {
textLabel?.text = item.title