diff --git a/CHANGELOG.md b/CHANGELOG.md
index aafb27d..af6e31e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 1.7.0
+
+- Adds new `HeaderFooterReusable` protocol to allow providing separate `Reusable` types for rendering a section's header and footer.
+- Adds letter spacing and line height to `TextStyle`.
+- Adds target offset to `willEndDragging` signal of `ScrollViewDelegate`.
+- Adds will display cell signal to `CollectionViewDelegate`.
+
## 1.6.3
- Performace. Added custom `count` implementation for `TableSection` to improve performance of e.g. `Table.isValidIndex` that might be called a lot for large tables.
diff --git a/Documentation/Tables.md b/Documentation/Tables.md
index cdf293f..39c0f59 100644
--- a/Documentation/Tables.md
+++ b/Documentation/Tables.md
@@ -77,6 +77,28 @@ If you are ok with losing type information you can also consider using the `Mixe
var mixedTable = Table<(), MixedReusable>(rows: [.init(1), .init("A"), .init("B"), .init(2)])
```
+## HeaderFooterReusable
+
+If you conform your `Table`'s `Section` type to `Reusable` a table's section will be rendered by the view provided by `makeAndConfigure()`. However if you like to provide both a header and a footer view from your section model data, you can conform your `Section` type to `HeaderFooterReusable` and provide separate header and footer types for rendering:
+
+```swift
+struct MySection { ... }
+
+extension MySection: HeaderFooterReusable {
+ var header: MyHeaderType { ... }
+ var footer: MyFooterType { ... }
+}
+```
+
+As it is common with header and footer that are just strings, Form includes the `HeaderFooter` type for your convenience:
+
+```swift
+struct HeaderFooter: HeaderFooterReusable, Hashable {
+ var header: String
+ var footer: String
+}
+```
+
## TableKit
Once you have your data in a `Table` and your `Row` and `Section` types conforming to `Reusable`, you can construct a `TableKit` that will provide a `UITableView` set up with a proper data source and delegate:
diff --git a/Examples/Demo/Example/Contents.swift b/Examples/Demo/Example/Contents.swift
index 11601f4..6045f35 100644
--- a/Examples/Demo/Example/Contents.swift
+++ b/Examples/Demo/Example/Contents.swift
@@ -116,6 +116,10 @@ extension UIViewController {
bag += section.appendRow(title: "TableKit and Nested Either Reusable").append(.chevron).onValueDisposePrevious {
present { $0.presentTableUsingKitAndNestedEitherReusable(style: style) }
}
+
+ bag += section.appendRow(title: "TableKit and HeaderFooterReusable").append(.chevron).onValueDisposePrevious {
+ present { $0.presentTableUsingKitAndHeaderFooterReusable(style: style) }
+ }
}
bag += self.install(form)
diff --git a/Examples/Demo/Example/CustomStyle.swift b/Examples/Demo/Example/CustomStyle.swift
index affb9aa..fb94e62 100644
--- a/Examples/Demo/Example/CustomStyle.swift
+++ b/Examples/Demo/Example/CustomStyle.swift
@@ -86,7 +86,7 @@ extension TextStyle {
static let regularButton = TextStyle(font: .regularButton, color: .mintGreenDark, alignment: .center)
static let disabledButton = TextStyle(font: .regularButton, color: .textGray, alignment: .center)
static let whiteButton = TextStyle(font: .regularButton, color: .white, alignment: .center)
- static let headerText = TextStyle(font: .headerText, color: .textGray).restyled { $0.kerning = 0.8 }.uppercased
+ static let headerText = TextStyle(font: .headerText, color: .textGray).restyled { $0.letterSpacing = 0.8 }.uppercased
static let footer = smallText.centerAligned.multilined()
static let headerBlack = headerText.colored(.black).multilined()
static let header = headerText.multilined()
diff --git a/Examples/Demo/Example/Tables.swift b/Examples/Demo/Example/Tables.swift
index edc41dc..ab114f5 100644
--- a/Examples/Demo/Example/Tables.swift
+++ b/Examples/Demo/Example/Tables.swift
@@ -195,6 +195,21 @@ extension UIViewController {
return bag
}
+
+ func presentTableUsingKitAndHeaderFooterReusable(style: DynamicTableViewFormStyle) -> Disposable {
+ displayableTitle = "TableKit and HeaderFooterReusable"
+ let bag = DisposeBag()
+
+ let tableKit = TableKit(table: sectionTable, style: style, bag: bag)
+ bag += self.install(tableKit.view)
+
+ bag += self.navigationItem.addItem(UIBarButtonItem(title: "Swap"), position: .right).onValue {
+ swap(§ionTable, &swapSectionTable)
+ tableKit.set(sectionTable)
+ }
+
+ return bag
+ }
}
private var table = Table(sections: [("Header 1", 0..<5), ("Header 2", 5..<10)])
@@ -220,3 +235,6 @@ extension Double: Reusable {
})
}
}
+
+private var sectionTable = Table(sections: [(HeaderFooter(header: "Header 1", footer: "Footer 1"), 0..<5), (HeaderFooter(header: "Header 2", footer: "Footer 2"), 5..<10)])
+private var swapSectionTable = Table(sections: [(HeaderFooter(header: "Header 1", footer: "Footer 1"), 0..<2), (HeaderFooter(header: "Header 1b", footer: "Footer 1b"), 3..<7), (HeaderFooter(header: "Header 2", footer: "Footer 2"), 7..<10)])
diff --git a/Form/Info.plist b/Form/Info.plist
index 2bd8f0d..01a700f 100644
--- a/Form/Info.plist
+++ b/Form/Info.plist
@@ -15,7 +15,7 @@