added TableDirector file
This commit is contained in:
parent
f8c659f069
commit
73ea2cf573
|
|
@ -0,0 +1,176 @@
|
|||
//
|
||||
// Copyright (c) 2015 Max Sokolov https://twitter.com/max_sokolov
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Responsible for table view's datasource and delegate.
|
||||
*/
|
||||
public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
private weak var tableView: UITableView!
|
||||
private var sections = [TableSectionBuilder]()
|
||||
|
||||
public init(tableView: UITableView) {
|
||||
super.init()
|
||||
|
||||
self.tableView = tableView
|
||||
self.tableView.delegate = self
|
||||
self.tableView.dataSource = self
|
||||
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didReceiveAction:", name: kActionPerformedNotificationKey, object: nil)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
NSNotificationCenter.defaultCenter().removeObserver(self)
|
||||
}
|
||||
|
||||
// MARK: Public methods
|
||||
|
||||
public func appendSection(section: TableSectionBuilder) {
|
||||
sections.append(section)
|
||||
}
|
||||
|
||||
public func appendSections(sections: [TableSectionBuilder]) {
|
||||
self.sections.appendContentsOf(sections)
|
||||
}
|
||||
|
||||
// MARK: Private methods
|
||||
|
||||
/**
|
||||
Find a row builder that responsible for building a row from cell with given item type.
|
||||
|
||||
- Parameters:
|
||||
- indexPath: path of cell to dequeue
|
||||
|
||||
- Returns: A touple - (builder, builderItemIndex)
|
||||
*/
|
||||
private func builderAtIndexPath(indexPath: NSIndexPath) -> (RowBuilder, Int) {
|
||||
|
||||
return sections[indexPath.section].builderAtIndex(indexPath.row)!
|
||||
}
|
||||
|
||||
private func triggerAction(action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> AnyObject? {
|
||||
|
||||
let builder = builderAtIndexPath(indexPath)
|
||||
return builder.0.triggerAction(action.rawValue, cell: cell, indexPath: indexPath, itemIndex: builder.1)
|
||||
}
|
||||
|
||||
internal func didReceiveAction(notification: NSNotification) {
|
||||
|
||||
if let action = notification.object as? Action, indexPath = tableView.indexPathForCell(action.cell) {
|
||||
|
||||
let builder = builderAtIndexPath(indexPath)
|
||||
builder.0.triggerAction(action.key, cell: action.cell, indexPath: indexPath, itemIndex: builder.1)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource - configuration
|
||||
|
||||
public func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
||||
|
||||
return sections.count
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return sections[section].numberOfRowsInSection
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let builder = builderAtIndexPath(indexPath)
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier(builder.0.reusableIdentifier, forIndexPath: indexPath)
|
||||
|
||||
builder.0.triggerAction(ActionType.configure.rawValue, cell: cell, indexPath: indexPath, itemIndex: builder.1)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource - section setup
|
||||
|
||||
public func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return sections[section].headerTitle
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||
|
||||
return sections[section].footerTitle
|
||||
}
|
||||
|
||||
// MARK: UITableViewDelegate - section setup
|
||||
|
||||
public func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
|
||||
return sections[section].headerView
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
|
||||
return sections[section].footerView
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
|
||||
return sections[section].headerHeight
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||
|
||||
return sections[section].footerHeight
|
||||
}
|
||||
|
||||
// MARK: UITableViewDelegate - actions
|
||||
|
||||
public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
let cell = tableView.cellForRowAtIndexPath(indexPath)
|
||||
|
||||
if triggerAction(.click, cell: cell, indexPath: indexPath) != nil {
|
||||
tableView.deselectRowAtIndexPath(indexPath, animated: true)
|
||||
} else {
|
||||
triggerAction(.select, cell: cell, indexPath: indexPath)
|
||||
}
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
triggerAction(.deselect, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath)
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
triggerAction(.willDisplay, cell: cell, indexPath: indexPath)
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
|
||||
|
||||
return triggerAction(.shouldHighlight, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? Bool ?? true
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
|
||||
|
||||
return triggerAction(.height, cell: nil, indexPath: indexPath) as? CGFloat ?? tableView.rowHeight
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import Foundation
|
|||
|
||||
/**
|
||||
Responsible for building a certain table view section.
|
||||
Can host several row builders.
|
||||
*/
|
||||
public class TableSectionBuilder {
|
||||
|
||||
|
|
|
|||
|
|
@ -103,158 +103,4 @@ public protocol RowBuilder {
|
|||
var reusableIdentifier: String { get }
|
||||
|
||||
func triggerAction(key: String, cell: UITableViewCell?, indexPath: NSIndexPath, itemIndex: Int) -> AnyObject?
|
||||
}
|
||||
|
||||
/**
|
||||
Responsible for table view's datasource and delegate.
|
||||
*/
|
||||
public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
private weak var tableView: UITableView!
|
||||
private var sections = [TableSectionBuilder]()
|
||||
|
||||
public init(tableView: UITableView) {
|
||||
super.init()
|
||||
|
||||
self.tableView = tableView
|
||||
self.tableView.delegate = self
|
||||
self.tableView.dataSource = self
|
||||
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didReceiveAction:", name: kActionPerformedNotificationKey, object: nil)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
NSNotificationCenter.defaultCenter().removeObserver(self)
|
||||
}
|
||||
|
||||
// MARK: Public methods
|
||||
|
||||
public func appendSection(section: TableSectionBuilder) {
|
||||
sections.append(section)
|
||||
}
|
||||
|
||||
public func appendSections(sections: [TableSectionBuilder]) {
|
||||
self.sections.appendContentsOf(sections)
|
||||
}
|
||||
|
||||
// MARK: Private methods
|
||||
|
||||
/**
|
||||
Find a row builder that responsible for building a row from cell with given item type.
|
||||
|
||||
- Parameters:
|
||||
- indexPath: path of cell to dequeue
|
||||
|
||||
- Returns: A touple - (builder, builderItemIndex)
|
||||
*/
|
||||
private func builderAtIndexPath(indexPath: NSIndexPath) -> (RowBuilder, Int) {
|
||||
|
||||
return sections[indexPath.section].builderAtIndex(indexPath.row)!
|
||||
}
|
||||
|
||||
private func triggerAction(action: ActionType, cell: UITableViewCell?, indexPath: NSIndexPath) -> AnyObject? {
|
||||
|
||||
let builder = builderAtIndexPath(indexPath)
|
||||
return builder.0.triggerAction(action.rawValue, cell: cell, indexPath: indexPath, itemIndex: builder.1)
|
||||
}
|
||||
|
||||
internal func didReceiveAction(notification: NSNotification) {
|
||||
|
||||
if let action = notification.object as? Action, indexPath = tableView.indexPathForCell(action.cell) {
|
||||
|
||||
let builder = builderAtIndexPath(indexPath)
|
||||
builder.0.triggerAction(action.key, cell: action.cell, indexPath: indexPath, itemIndex: builder.1)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource - configuration
|
||||
|
||||
public func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
||||
|
||||
return sections.count
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return sections[section].numberOfRowsInSection
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let builder = builderAtIndexPath(indexPath)
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier(builder.0.reusableIdentifier, forIndexPath: indexPath)
|
||||
|
||||
builder.0.triggerAction(ActionType.configure.rawValue, cell: cell, indexPath: indexPath, itemIndex: builder.1)
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource - section setup
|
||||
|
||||
public func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return sections[section].headerTitle
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||
|
||||
return sections[section].footerTitle
|
||||
}
|
||||
|
||||
// MARK: UITableViewDelegate - section setup
|
||||
|
||||
public func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
|
||||
return sections[section].headerView
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
|
||||
return sections[section].footerView
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
|
||||
return sections[section].headerHeight
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||
|
||||
return sections[section].footerHeight
|
||||
}
|
||||
|
||||
// MARK: UITableViewDelegate - actions
|
||||
|
||||
public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
let cell = tableView.cellForRowAtIndexPath(indexPath)
|
||||
|
||||
if triggerAction(.click, cell: cell, indexPath: indexPath) != nil {
|
||||
tableView.deselectRowAtIndexPath(indexPath, animated: true)
|
||||
} else {
|
||||
triggerAction(.select, cell: cell, indexPath: indexPath)
|
||||
}
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
triggerAction(.deselect, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath)
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
triggerAction(.willDisplay, cell: cell, indexPath: indexPath)
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
|
||||
|
||||
return triggerAction(.shouldHighlight, cell: tableView.cellForRowAtIndexPath(indexPath), indexPath: indexPath) as? Bool ?? true
|
||||
}
|
||||
|
||||
public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
|
||||
|
||||
return triggerAction(.height, cell: nil, indexPath: indexPath) as? CGFloat ?? tableView.rowHeight
|
||||
}
|
||||
}
|
||||
|
|
@ -7,20 +7,22 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
508B71841BF48DD300272920 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508B71831BF48DD300272920 /* TableSectionBuilder.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
508B71861BF48E0D00272920 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508B71851BF48E0D00272920 /* TableRowBuilder.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
508B71841BF48DD300272920 /* TableSectionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508B71831BF48DD300272920 /* TableSectionBuilder.swift */; };
|
||||
508B71861BF48E0D00272920 /* TableRowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508B71851BF48E0D00272920 /* TableRowBuilder.swift */; };
|
||||
DA1BCD0F1BF5472C00CC0479 /* TableDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1BCD0E1BF5472C00CC0479 /* TableDirector.swift */; };
|
||||
DAB7EB2B1BEF787300D2AD5E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB2A1BEF787300D2AD5E /* AppDelegate.swift */; };
|
||||
DAB7EB2D1BEF787300D2AD5E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB2C1BEF787300D2AD5E /* ViewController.swift */; };
|
||||
DAB7EB301BEF787300D2AD5E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAB7EB2E1BEF787300D2AD5E /* Main.storyboard */; };
|
||||
DAB7EB321BEF787300D2AD5E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DAB7EB311BEF787300D2AD5E /* Assets.xcassets */; };
|
||||
DAB7EB351BEF787300D2AD5E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAB7EB331BEF787300D2AD5E /* LaunchScreen.storyboard */; };
|
||||
DAB7EB3E1BEF78A400D2AD5E /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB3D1BEF78A400D2AD5E /* Tablet.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
DAB7EB401BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB3F1BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
DAB7EB3E1BEF78A400D2AD5E /* Tablet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB3D1BEF78A400D2AD5E /* Tablet.swift */; };
|
||||
DAB7EB401BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB7EB3F1BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
508B71831BF48DD300272920 /* TableSectionBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableSectionBuilder.swift; sourceTree = "<group>"; };
|
||||
508B71851BF48E0D00272920 /* TableRowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableRowBuilder.swift; sourceTree = "<group>"; };
|
||||
DA1BCD0E1BF5472C00CC0479 /* TableDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDirector.swift; sourceTree = "<group>"; };
|
||||
DAB7EB271BEF787300D2AD5E /* TabletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DAB7EB2A1BEF787300D2AD5E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
DAB7EB2C1BEF787300D2AD5E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -78,8 +80,9 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
DAB7EB3D1BEF78A400D2AD5E /* Tablet.swift */,
|
||||
508B71831BF48DD300272920 /* TableSectionBuilder.swift */,
|
||||
DA1BCD0E1BF5472C00CC0479 /* TableDirector.swift */,
|
||||
508B71851BF48E0D00272920 /* TableRowBuilder.swift */,
|
||||
508B71831BF48DD300272920 /* TableSectionBuilder.swift */,
|
||||
);
|
||||
name = Tablet;
|
||||
path = ../Tablet;
|
||||
|
|
@ -159,6 +162,7 @@
|
|||
DAB7EB2D1BEF787300D2AD5E /* ViewController.swift in Sources */,
|
||||
DAB7EB3E1BEF78A400D2AD5E /* Tablet.swift in Sources */,
|
||||
508B71861BF48E0D00272920 /* TableRowBuilder.swift in Sources */,
|
||||
DA1BCD0F1BF5472C00CC0479 /* TableDirector.swift in Sources */,
|
||||
DAB7EB401BEFD07E00D2AD5E /* ConfigurableTableViewCell.swift in Sources */,
|
||||
DAB7EB2B1BEF787300D2AD5E /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -19,7 +19,7 @@ class ViewController: UIViewController {
|
|||
tableDirector = TableDirector(tableView: tableView)
|
||||
|
||||
let rowBuilder = TableRowBuilder<Int, UITableViewCell>(items: [1, 2, 3, 4], id: "cell")
|
||||
.action(.configure) { data -> Void in
|
||||
.action(.configure) { data in
|
||||
|
||||
data.cell?.textLabel?.text = "\(data.item)"
|
||||
}
|
||||
|
|
@ -31,18 +31,18 @@ class ViewController: UIViewController {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
let configurableRowBuilder = TableConfigurableRowBuilder<String, ConfigurableTableViewCell>(items: ["5", "6", "7", "8"])
|
||||
.action(kConfigurableTableViewCellButtonClickedAction) { data -> Void in
|
||||
|
||||
print("custom action indexPath: \(data.indexPath), item: \(data.item)")
|
||||
}
|
||||
.action(.click) { data -> Void in
|
||||
|
||||
data.cell!.textLabel?.text = ""
|
||||
|
||||
print("custom action indexPath: \(data.indexPath), item: \(data.item)")
|
||||
}
|
||||
.action(kConfigurableTableViewCellButtonClickedAction) { data in
|
||||
|
||||
print("custom action indexPath: \(data.indexPath), item: \(data.item)")
|
||||
}
|
||||
|
||||
let sectionBuilder = TableSectionBuilder(headerTitle: "Tablet", footerTitle: "Deal with table view like a boss.", rowBuilders: [rowBuilder, configurableRowBuilder])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue