diff --git a/Demo/Classes/Presentation/Controllers/AutolayoutCellsController.swift b/Demo/Classes/Presentation/Controllers/AutolayoutCellsController.swift index 618e02a..9340070 100644 --- a/Demo/Classes/Presentation/Controllers/AutolayoutCellsController.swift +++ b/Demo/Classes/Presentation/Controllers/AutolayoutCellsController.swift @@ -14,6 +14,7 @@ class AutolayoutCellsController: UIViewController { @IBOutlet weak var tableView: UITableView! { didSet { tableDirector = TableDirector(tableView: tableView) + tableDirector.shouldUsePrototypeCellHeightCalculation = true } } var tableDirector: TableDirector! @@ -26,7 +27,7 @@ class AutolayoutCellsController: UIViewController { let section = TableSection() var rows = 0 - while rows <= 10 { + while rows <= 1000 { rows += 1 let row = TableRow(item: ()) diff --git a/Demo/Classes/Presentation/Controllers/MainController.swift b/Demo/Classes/Presentation/Controllers/MainController.swift index b57a0db..bad5564 100644 --- a/Demo/Classes/Presentation/Controllers/MainController.swift +++ b/Demo/Classes/Presentation/Controllers/MainController.swift @@ -34,7 +34,7 @@ class MainController: UIViewController { break } } - + let rows: [Row] = [ TableRow(item: "Autolayout cells", actions: [clickAction]), diff --git a/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift b/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift index ec505d6..ff4219e 100644 --- a/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift +++ b/Demo/Classes/Presentation/Views/AutolayoutTableViewCell.swift @@ -18,9 +18,9 @@ class AutolayoutTableViewCell: UITableViewCell, ConfigurableCell { @IBOutlet var titleLabel: UILabel! @IBOutlet var subtitleLabel: UILabel! - + static var estimatedHeight: CGFloat? { - return 500 + return 700 } func configure(with string: T) { @@ -28,4 +28,13 @@ class AutolayoutTableViewCell: UITableViewCell, ConfigurableCell { titleLabel.text = LoremIpsumTitle subtitleLabel.text = LoremIpsumBody } + + override func layoutSubviews() { + super.layoutSubviews() + + contentView.layoutIfNeeded() + + titleLabel.preferredMaxLayoutWidth = titleLabel.bounds.size.width + subtitleLabel.preferredMaxLayoutWidth = subtitleLabel.bounds.size.width + } } \ No newline at end of file diff --git a/Demo/Classes/Presentation/Views/NibTableViewCell.xib b/Demo/Classes/Presentation/Views/NibTableViewCell.xib index 1b9ae31..34c76d1 100644 --- a/Demo/Classes/Presentation/Views/NibTableViewCell.xib +++ b/Demo/Classes/Presentation/Views/NibTableViewCell.xib @@ -1,5 +1,5 @@ - + @@ -11,19 +11,21 @@ - + - - + + + + diff --git a/README.md b/README.md index 2219125..c366ca1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Build Status Swift 2.2 compatible Carthage compatible - CocoaPods compatible + CocoaPods compatible Platform iOS License: MIT

diff --git a/Sources/ConfigurableCell.swift b/Sources/ConfigurableCell.swift index 18035ff..5ec461e 100644 --- a/Sources/ConfigurableCell.swift +++ b/Sources/ConfigurableCell.swift @@ -42,7 +42,7 @@ public extension ConfigurableCell where Self: UITableViewCell { static var estimatedHeight: CGFloat? { get { - return UITableViewAutomaticDimension + return nil } } diff --git a/Sources/HeightStrategy.swift b/Sources/HeightStrategy.swift index 66eec6f..66b715b 100644 --- a/Sources/HeightStrategy.swift +++ b/Sources/HeightStrategy.swift @@ -49,12 +49,18 @@ public class PrototypeHeightStrategy: CellHeightCalculatable { return height } - guard let cell = tableView.dequeueReusableCellWithIdentifier(row.reuseIdentifier) else { return 0 } + var prototypeCell = prototypes[row.reuseIdentifier] + if prototypeCell == nil { - cell.bounds = CGRectMake(0, 0, tableView.bounds.size.width, cell.bounds.height) + prototypeCell = tableView.dequeueReusableCellWithIdentifier(row.reuseIdentifier) + prototypes[row.reuseIdentifier] = prototypeCell + } + guard let cell = prototypeCell else { return 0 } + row.configure(cell) - + + cell.bounds = CGRectMake(0, 0, tableView.bounds.size.width, cell.bounds.height) cell.setNeedsLayout() cell.layoutIfNeeded() @@ -66,6 +72,19 @@ public class PrototypeHeightStrategy: CellHeightCalculatable { } public func estimatedHeight(row: Row, path: NSIndexPath) -> CGFloat { + + guard let tableView = tableView else { return 0 } + + let hash = row.hashValue ^ Int(tableView.bounds.size.width).hashValue + + if let height = cachedHeights[hash] { + return height + } + + if let estimatedHeight = row.estimatedHeight where estimatedHeight > 0 { + return estimatedHeight + } + return UITableViewAutomaticDimension } diff --git a/Sources/TableCellAction.swift b/Sources/TableCellAction.swift index 8c81bef..5f12ca8 100644 --- a/Sources/TableCellAction.swift +++ b/Sources/TableCellAction.swift @@ -26,7 +26,7 @@ struct TableKitNotifications { /** A custom action that you can trigger from your cell. - You can eacily catch actions using a chaining manner with your row builder. + You can easily catch actions using a chaining manner with your row. */ public class TableCellAction { diff --git a/Sources/TableCellManager.swift b/Sources/TableCellRegisterer.swift similarity index 98% rename from Sources/TableCellManager.swift rename to Sources/TableCellRegisterer.swift index 891266e..393afa0 100644 --- a/Sources/TableCellManager.swift +++ b/Sources/TableCellRegisterer.swift @@ -20,8 +20,8 @@ import UIKit -class TableCellManager { - +class TableCellRegisterer { + private var registeredIds = Set() private weak var tableView: UITableView? diff --git a/Sources/TableDirector.swift b/Sources/TableDirector.swift index 6f7c093..88c90ea 100644 --- a/Sources/TableDirector.swift +++ b/Sources/TableDirector.swift @@ -30,7 +30,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate private weak var scrollDelegate: UIScrollViewDelegate? private var heightStrategy: CellHeightCalculatable? - private var cellManager: TableCellManager? + private var cellRegisterer: TableCellRegisterer? public var shouldUsePrototypeCellHeightCalculation: Bool = false { didSet { @@ -48,7 +48,7 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate super.init() if shouldUseAutomaticCellRegistration { - self.cellManager = TableCellManager(tableView: tableView) + self.cellRegisterer = TableCellRegisterer(tableView: tableView) } self.scrollDelegate = scrollDelegate @@ -98,14 +98,18 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate public func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { let row = sections[indexPath.section].rows[indexPath.row] + + cellRegisterer?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier) + return row.estimatedHeight ?? heightStrategy?.estimatedHeight(row, path: indexPath) ?? UITableViewAutomaticDimension } public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { let row = sections[indexPath.section].rows[indexPath.row] + let rowHeight = invoke(action: .height, cell: nil, indexPath: indexPath) as? CGFloat - + return rowHeight ?? row.defaultHeight ?? heightStrategy?.height(row, path: indexPath) ?? UITableViewAutomaticDimension } @@ -122,9 +126,6 @@ public class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let row = sections[indexPath.section].rows[indexPath.row] - - cellManager?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier) - let cell = tableView.dequeueReusableCellWithIdentifier(row.reuseIdentifier, forIndexPath: indexPath) if cell.frame.size.width != tableView.frame.size.width { diff --git a/Sources/TableSection.swift b/Sources/TableSection.swift index 02ff134..904bfbd 100644 --- a/Sources/TableSection.swift +++ b/Sources/TableSection.swift @@ -84,13 +84,8 @@ public class TableSection { self.rows.insertContentsOf(rows, at: index) } - public func replace(rowAt index: Int, with row: Row) -> Bool { - - if index >= 0 && index < rows.count { - rows[index] = row - return true - } - return false + public func replace(rowAt index: Int, with row: Row) { + rows[index] = row } public func delete(index index: Int) { diff --git a/TableKit.podspec b/TableKit.podspec index 06d3c55..5380a89 100644 --- a/TableKit.podspec +++ b/TableKit.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |s| s.name = 'TableKit' s.module_name = 'TableKit' - s.version = '1.1.2' + s.version = '1.2.0' s.homepage = 'https://github.com/maxsokolov/TableKit' s.summary = 'Type-safe declarative table views. Swift 2.2 is required.' diff --git a/TableKit.xcodeproj/project.pbxproj b/TableKit.xcodeproj/project.pbxproj index 32e8324..fe0e2a7 100644 --- a/TableKit.xcodeproj/project.pbxproj +++ b/TableKit.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 50CF6E6B1D6704FE004746FF /* TableCellManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellManager.swift */; }; + 50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; }; DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */; }; DA9EA7B01D0EC2C90021F650 /* HeightStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A71D0EC2C90021F650 /* HeightStrategy.swift */; }; DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A81D0EC2C90021F650 /* Operators.swift */; }; @@ -31,7 +31,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 50CF6E6A1D6704FE004746FF /* TableCellManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellManager.swift; sourceTree = ""; }; + 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = ""; }; DA9EA7561D0B679A0021F650 /* TableKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; DA9EA7A71D0EC2C90021F650 /* HeightStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeightStrategy.swift; sourceTree = ""; }; @@ -89,7 +89,7 @@ isa = PBXGroup; children = ( DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */, - 50CF6E6A1D6704FE004746FF /* TableCellManager.swift */, + 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */, DA9EA7AB1D0EC2C90021F650 /* TableRow.swift */, DA9EA7AC1D0EC2C90021F650 /* TableRowAction.swift */, DA9EA7AE1D0EC2C90021F650 /* TableSection.swift */, @@ -225,7 +225,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 50CF6E6B1D6704FE004746FF /* TableCellManager.swift in Sources */, + 50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */, DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */, DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */, DA9EA7B71D0EC2C90021F650 /* TableSection.swift in Sources */,