From 6eaf2cf3a26a36a1473d880ee3b3bb2045e9059d Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Mon, 10 Dec 2018 17:15:43 +0300 Subject: [PATCH 1/8] Add Expandable protocol to expand/collapse cells --- Sources/ConfigurableCell.swift | 3 ++ Sources/Expandable.swift | 54 +++++++++++++++++++ Sources/ExpandableCellHeightCalculator.swift | 55 ++++++++++++++++++++ Sources/ExpandableCellViewModel.swift | 5 ++ Sources/UITableViewCell+Extensions.swift | 27 ++++++++++ TableKit.xcodeproj/project.pbxproj | 30 ++++++++--- 6 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 Sources/Expandable.swift create mode 100644 Sources/ExpandableCellHeightCalculator.swift create mode 100644 Sources/ExpandableCellViewModel.swift create mode 100644 Sources/UITableViewCell+Extensions.swift diff --git a/Sources/ConfigurableCell.swift b/Sources/ConfigurableCell.swift index dee4db2..6454dc3 100644 --- a/Sources/ConfigurableCell.swift +++ b/Sources/ConfigurableCell.swift @@ -25,7 +25,10 @@ public protocol ConfigurableCell { associatedtype CellData static var reuseIdentifier: String { get } + + @available(*, deprecated, message: "For static cells use defaultHeight, height of self-sized cells will be calculated automatically") static var estimatedHeight: CGFloat? { get } + static var defaultHeight: CGFloat? { get } func configure(with _: CellData) diff --git a/Sources/Expandable.swift b/Sources/Expandable.swift new file mode 100644 index 0000000..51112de --- /dev/null +++ b/Sources/Expandable.swift @@ -0,0 +1,54 @@ +import UIKit + +public protocol Expandable { + + associatedtype ViewModelType: ExpandableCellViewModel + + var viewModel: ViewModelType? { get } + + func configureAppearance(isCollapsed: Bool) + +} + +extension Expandable where Self: UITableViewCell & ConfigurableCell { + + public func toggleState(animated: Bool = true, + animationDuration: TimeInterval = 0.3) { + + guard let tableView = tableView, + let viewModel = viewModel else { + return + } + + let contentOffset = tableView.contentOffset + + if animated { + UIView.animate(withDuration: animationDuration, + animations: { [weak self] in + self?.applyChanges(isCollapsed: !viewModel.isCollapsed) + }, completion: { _ in + viewModel.isCollapsed.toggle() + }) + } else { + applyChanges(isCollapsed: !viewModel.isCollapsed) + viewModel.isCollapsed.toggle() + } + + tableView.beginUpdates() + tableView.endUpdates() + + tableView.setContentOffset(contentOffset, animated: false) + } + + private func applyChanges(isCollapsed: Bool) { + configureAppearance(isCollapsed: isCollapsed) + layoutIfNeeded() + + if let indexPath = indexPath, + let tableDirector = (tableView?.delegate as? TableDirector), + let cellHeightCalculator = tableDirector.rowHeightCalculator as? ExpandableCellHeightCalculator { + cellHeightCalculator.updateCached(height: height, for: indexPath) + } + } + +} diff --git a/Sources/ExpandableCellHeightCalculator.swift b/Sources/ExpandableCellHeightCalculator.swift new file mode 100644 index 0000000..a9bf8ee --- /dev/null +++ b/Sources/ExpandableCellHeightCalculator.swift @@ -0,0 +1,55 @@ +import UIKit + +public final class ExpandableCellHeightCalculator: RowHeightCalculator { + + private(set) weak var tableView: UITableView? + + private var prototypes = [String: UITableViewCell]() + + private var cachedHeights = [IndexPath: CGFloat]() + + public init(tableView: UITableView?) { + self.tableView = tableView + } + + public func updateCached(height: CGFloat, for indexPath: IndexPath) { + cachedHeights[indexPath] = height + } + + public func height(forRow row: Row, at indexPath: IndexPath) -> CGFloat { + + guard let tableView = tableView else { + return 0 + } + + if let height = cachedHeights[indexPath] { + return height + } + + var prototypeCell = prototypes[row.reuseIdentifier] + if prototypeCell == nil { + prototypeCell = tableView.dequeueReusableCell(withIdentifier: row.reuseIdentifier) + prototypes[row.reuseIdentifier] = prototypeCell + } + + guard let cell = prototypeCell else { + return 0 + } + + row.configure(cell) + cell.layoutIfNeeded() + + let height = cell.height + cachedHeights[indexPath] = height + return height + } + + public func estimatedHeight(forRow row: Row, at indexPath: IndexPath) -> CGFloat { + return height(forRow: row, at: indexPath) + } + + public func invalidate() { + cachedHeights.removeAll() + } + +} diff --git a/Sources/ExpandableCellViewModel.swift b/Sources/ExpandableCellViewModel.swift new file mode 100644 index 0000000..f3dd8ea --- /dev/null +++ b/Sources/ExpandableCellViewModel.swift @@ -0,0 +1,5 @@ +public protocol ExpandableCellViewModel: class { + + var isCollapsed: Bool { get set } + +} diff --git a/Sources/UITableViewCell+Extensions.swift b/Sources/UITableViewCell+Extensions.swift new file mode 100644 index 0000000..dee1042 --- /dev/null +++ b/Sources/UITableViewCell+Extensions.swift @@ -0,0 +1,27 @@ +import UIKit + +extension UITableViewCell { + + public var tableView: UITableView? { + var view = superview + + while view != nil && !(view is UITableView) { + view = view?.superview + } + + return view as? UITableView + } + + public var indexPath: IndexPath? { + guard let indexPath = tableView?.indexPath(for: self) else { + return nil + } + + return indexPath + } + + public var height: CGFloat { + return contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height + } + +} diff --git a/TableKit.xcodeproj/project.pbxproj b/TableKit.xcodeproj/project.pbxproj index b30ee04..de4d250 100644 --- a/TableKit.xcodeproj/project.pbxproj +++ b/TableKit.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */; }; + 3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */; }; + 3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78721BE9EB2001DF9E7 /* Expandable.swift */; }; + 3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */; }; 320C5280218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */; }; 50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; }; 50E858581DB153F500A9AA55 /* TableKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E858571DB153F500A9AA55 /* TableKit.swift */; }; @@ -33,6 +37,10 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellHeightCalculator.swift; sourceTree = ""; }; + 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+Extensions.swift"; sourceTree = ""; }; + 3201E78721BE9EB2001DF9E7 /* Expandable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Expandable.swift; sourceTree = ""; }; + 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewModel.swift; sourceTree = ""; }; 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccurateCellHeightCalculator.swift; sourceTree = ""; }; 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = ""; }; 50E858571DB153F500A9AA55 /* TableKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKit.swift; sourceTree = ""; }; @@ -92,17 +100,21 @@ DA9EA7A51D0EC2B90021F650 /* Sources */ = { isa = PBXGroup; children = ( - 50E858571DB153F500A9AA55 /* TableKit.swift */, - DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */, + 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */, + DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */, + 3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */, + DA9EA7A81D0EC2C90021F650 /* Operators.swift */, + DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */, 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */, + DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */, + 50E858571DB153F500A9AA55 /* TableKit.swift */, + DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */, DA9EA7AB1D0EC2C90021F650 /* TableRow.swift */, DA9EA7AC1D0EC2C90021F650 /* TableRowAction.swift */, DA9EA7AE1D0EC2C90021F650 /* TableSection.swift */, - DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */, - DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */, - DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */, - DA9EA7A81D0EC2C90021F650 /* Operators.swift */, - 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */, + 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */, + 3201E78721BE9EB2001DF9E7 /* Expandable.swift */, + 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */, ); path = Sources; sourceTree = ""; @@ -233,14 +245,18 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */, 50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */, DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */, DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */, + 3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */, 320C5280218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift in Sources */, DA9EA7B71D0EC2C90021F650 /* TableSection.swift in Sources */, DA9EA7B01D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift in Sources */, + 3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */, DA9EA7B51D0EC2C90021F650 /* TableRowAction.swift in Sources */, DA9EA7B21D0EC2C90021F650 /* TableCellAction.swift in Sources */, + 3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */, DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */, DA9EA7B41D0EC2C90021F650 /* TableRow.swift in Sources */, 50E858581DB153F500A9AA55 /* TableKit.swift in Sources */, From 5982d5db3af123a39afb220771ff649748300e5a Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Tue, 11 Dec 2018 12:16:32 +0300 Subject: [PATCH 2/8] Use ExpandableCellHeightCalculator by default --- Sources/TableDirector.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/TableDirector.swift b/Sources/TableDirector.swift index c17ce2c..1a7724c 100644 --- a/Sources/TableDirector.swift +++ b/Sources/TableDirector.swift @@ -60,7 +60,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { self.cellRegisterer = TableCellRegisterer(tableView: tableView) } - self.rowHeightCalculator = cellHeightCalculator + self.rowHeightCalculator = cellHeightCalculator ?? ExpandableCellHeightCalculator(tableView: tableView) self.scrollDelegate = scrollDelegate self.tableView = tableView self.tableView?.delegate = self From e22ec03990f20f2328ebd9faaca80d129527563e Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Wed, 12 Dec 2018 19:03:16 +0300 Subject: [PATCH 3/8] Add layout type --- Sources/ConfigurableCell.swift | 7 +++++++ Sources/Expandable.swift | 2 +- Sources/ExpandableCellHeightCalculator.swift | 2 +- Sources/LayoutType.swift | 7 +++++++ Sources/TableKit.swift | 3 ++- Sources/TableRow.swift | 4 ++++ Sources/UITableViewCell+Extensions.swift | 9 +++++++-- TableKit.xcodeproj/project.pbxproj | 4 ++++ 8 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 Sources/LayoutType.swift diff --git a/Sources/ConfigurableCell.swift b/Sources/ConfigurableCell.swift index 6454dc3..2c1fb4e 100644 --- a/Sources/ConfigurableCell.swift +++ b/Sources/ConfigurableCell.swift @@ -31,6 +31,8 @@ public protocol ConfigurableCell { static var defaultHeight: CGFloat? { get } + static var layoutType: LayoutType { get } + func configure(with _: CellData) func height(for _: CellData) -> CGFloat @@ -57,4 +59,9 @@ public extension ConfigurableCell where Self: UITableViewCell { static var defaultHeight: CGFloat? { return nil } + + static var layoutType: LayoutType { + return .auto + } + } diff --git a/Sources/Expandable.swift b/Sources/Expandable.swift index 51112de..a2ca692 100644 --- a/Sources/Expandable.swift +++ b/Sources/Expandable.swift @@ -47,7 +47,7 @@ extension Expandable where Self: UITableViewCell & ConfigurableCell { if let indexPath = indexPath, let tableDirector = (tableView?.delegate as? TableDirector), let cellHeightCalculator = tableDirector.rowHeightCalculator as? ExpandableCellHeightCalculator { - cellHeightCalculator.updateCached(height: height, for: indexPath) + cellHeightCalculator.updateCached(height: height(layoutType: Self.layoutType), for: indexPath) } } diff --git a/Sources/ExpandableCellHeightCalculator.swift b/Sources/ExpandableCellHeightCalculator.swift index a9bf8ee..08bbecf 100644 --- a/Sources/ExpandableCellHeightCalculator.swift +++ b/Sources/ExpandableCellHeightCalculator.swift @@ -39,7 +39,7 @@ public final class ExpandableCellHeightCalculator: RowHeightCalculator { row.configure(cell) cell.layoutIfNeeded() - let height = cell.height + let height = cell.height(layoutType: row.layoutType) cachedHeights[indexPath] = height return height } diff --git a/Sources/LayoutType.swift b/Sources/LayoutType.swift new file mode 100644 index 0000000..328ba4c --- /dev/null +++ b/Sources/LayoutType.swift @@ -0,0 +1,7 @@ +public enum LayoutType { + + case manual + + case auto + +} diff --git a/Sources/TableKit.swift b/Sources/TableKit.swift index 91031b3..fed5e9c 100644 --- a/Sources/TableKit.swift +++ b/Sources/TableKit.swift @@ -59,7 +59,8 @@ public protocol Row: RowConfigurable, RowActionable, RowHashable { var reuseIdentifier: String { get } var cellType: AnyClass { get } - + + var layoutType: LayoutType { get } var estimatedHeight: CGFloat? { get } var defaultHeight: CGFloat? { get } } diff --git a/Sources/TableRow.swift b/Sources/TableRow.swift index 1c5eef0..491015e 100644 --- a/Sources/TableRow.swift +++ b/Sources/TableRow.swift @@ -41,6 +41,10 @@ open class TableRow: Row where CellType: UITableView open var defaultHeight: CGFloat? { return CellType.defaultHeight } + + open var layoutType: LayoutType { + return CellType.layoutType + } open var cellType: AnyClass { return CellType.self diff --git a/Sources/UITableViewCell+Extensions.swift b/Sources/UITableViewCell+Extensions.swift index dee1042..b65055a 100644 --- a/Sources/UITableViewCell+Extensions.swift +++ b/Sources/UITableViewCell+Extensions.swift @@ -20,8 +20,13 @@ extension UITableViewCell { return indexPath } - public var height: CGFloat { - return contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height + public func height(layoutType: LayoutType) -> CGFloat { + switch layoutType { + case .auto: + return contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height + case .manual: + return contentView.subviews.map { $0.frame.maxY }.max() ?? 0 + } } } diff --git a/TableKit.xcodeproj/project.pbxproj b/TableKit.xcodeproj/project.pbxproj index de4d250..068fb5f 100644 --- a/TableKit.xcodeproj/project.pbxproj +++ b/TableKit.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78721BE9EB2001DF9E7 /* Expandable.swift */; }; 3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */; }; 320C5280218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */; }; + 32BDFE9F21C167F400D0BBB4 /* LayoutType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */; }; 50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; }; 50E858581DB153F500A9AA55 /* TableKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E858571DB153F500A9AA55 /* TableKit.swift */; }; DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */; }; @@ -42,6 +43,7 @@ 3201E78721BE9EB2001DF9E7 /* Expandable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Expandable.swift; sourceTree = ""; }; 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewModel.swift; sourceTree = ""; }; 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccurateCellHeightCalculator.swift; sourceTree = ""; }; + 32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutType.swift; sourceTree = ""; }; 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = ""; }; 50E858571DB153F500A9AA55 /* TableKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKit.swift; sourceTree = ""; }; DA9EA7561D0B679A0021F650 /* TableKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -115,6 +117,7 @@ 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */, 3201E78721BE9EB2001DF9E7 /* Expandable.swift */, 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */, + 32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */, ); path = Sources; sourceTree = ""; @@ -256,6 +259,7 @@ 3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */, DA9EA7B51D0EC2C90021F650 /* TableRowAction.swift in Sources */, DA9EA7B21D0EC2C90021F650 /* TableCellAction.swift in Sources */, + 32BDFE9F21C167F400D0BBB4 /* LayoutType.swift in Sources */, 3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */, DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */, DA9EA7B41D0EC2C90021F650 /* TableRow.swift in Sources */, From 6ef5ad504eb3305db32ba98377bd896474914943 Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Wed, 12 Dec 2018 19:06:50 +0300 Subject: [PATCH 4/8] Add initState for Expandable --- Sources/Expandable.swift | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Sources/Expandable.swift b/Sources/Expandable.swift index a2ca692..847965f 100644 --- a/Sources/Expandable.swift +++ b/Sources/Expandable.swift @@ -12,6 +12,23 @@ public protocol Expandable { extension Expandable where Self: UITableViewCell & ConfigurableCell { + public func initState() { + guard let viewModel = viewModel else { + return + } + + changeState(isCollapsed: viewModel.isCollapsed) + } + + private func changeState(isCollapsed: Bool) { + // layout to get right frames, frame of bottom subview can be used to get expanded height + layoutIfNeeded() + + // apply changes + configureAppearance(isCollapsed: isCollapsed) + layoutIfNeeded() + } + public func toggleState(animated: Bool = true, animationDuration: TimeInterval = 0.3) { @@ -41,8 +58,7 @@ extension Expandable where Self: UITableViewCell & ConfigurableCell { } private func applyChanges(isCollapsed: Bool) { - configureAppearance(isCollapsed: isCollapsed) - layoutIfNeeded() + changeState(isCollapsed: isCollapsed) if let indexPath = indexPath, let tableDirector = (tableView?.delegate as? TableDirector), From 497b4e009c6815ce65e153e9f3e15b752593c23e Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Wed, 9 Jan 2019 16:04:32 +0300 Subject: [PATCH 5/8] Make ExpandableCellHeightCalculator optional, not default --- Sources/TableDirector.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/TableDirector.swift b/Sources/TableDirector.swift index 1a7724c..c17ce2c 100644 --- a/Sources/TableDirector.swift +++ b/Sources/TableDirector.swift @@ -60,7 +60,7 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate { self.cellRegisterer = TableCellRegisterer(tableView: tableView) } - self.rowHeightCalculator = cellHeightCalculator ?? ExpandableCellHeightCalculator(tableView: tableView) + self.rowHeightCalculator = cellHeightCalculator self.scrollDelegate = scrollDelegate self.tableView = tableView self.tableView?.delegate = self From 9d10bc18bf727d11bdae6448150d90068d203fd9 Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Wed, 9 Jan 2019 16:05:07 +0300 Subject: [PATCH 6/8] Remove manual height calculation functionality --- Sources/AccurateCellHeightCalculator.swift | 45 ---------------------- Sources/ConfigurableCell.swift | 9 ----- Sources/TableKit.swift | 1 - Sources/TableRow.swift | 7 +--- TableKit.xcodeproj/project.pbxproj | 4 -- 5 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 Sources/AccurateCellHeightCalculator.swift diff --git a/Sources/AccurateCellHeightCalculator.swift b/Sources/AccurateCellHeightCalculator.swift deleted file mode 100644 index d4190fb..0000000 --- a/Sources/AccurateCellHeightCalculator.swift +++ /dev/null @@ -1,45 +0,0 @@ -import UIKit - -public class AccurateCellHeightCalculator: RowHeightCalculator { - - private(set) weak var tableView: UITableView? - private var prototypes = [String: UITableViewCell]() - private var cachedHeights = [Int: CGFloat]() - - public init(tableView: UITableView?) { - self.tableView = tableView - } - - open func height(forRow row: Row, at indexPath: IndexPath) -> 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 - } - - var prototypeCell = prototypes[row.reuseIdentifier] - if prototypeCell == nil { - - prototypeCell = tableView.dequeueReusableCell(withIdentifier: row.reuseIdentifier) - prototypes[row.reuseIdentifier] = prototypeCell - } - - guard let cell = prototypeCell else { return 0 } - let height = row.height(for: cell) - - cachedHeights[hash] = height - - return height - } - - open func estimatedHeight(forRow row: Row, at indexPath: IndexPath) -> CGFloat { - return height(forRow: row, at: indexPath) - } - - open func invalidate() { - cachedHeights.removeAll() - } -} diff --git a/Sources/ConfigurableCell.swift b/Sources/ConfigurableCell.swift index 2c1fb4e..b7d9464 100644 --- a/Sources/ConfigurableCell.swift +++ b/Sources/ConfigurableCell.swift @@ -34,18 +34,9 @@ public protocol ConfigurableCell { static var layoutType: LayoutType { get } func configure(with _: CellData) - func height(for _: CellData) -> CGFloat } -public extension ConfigurableCell { - - func height(for _: CellData) -> CGFloat { - return UITableView.automaticDimension - } - -} - public extension ConfigurableCell where Self: UITableViewCell { static var reuseIdentifier: String { diff --git a/Sources/TableKit.swift b/Sources/TableKit.swift index fed5e9c..8206baf 100644 --- a/Sources/TableKit.swift +++ b/Sources/TableKit.swift @@ -32,7 +32,6 @@ public struct TableKitUserInfoKeys { public protocol RowConfigurable { func configure(_ cell: UITableViewCell) - func height(for _: UITableViewCell) -> CGFloat } diff --git a/Sources/TableRow.swift b/Sources/TableRow.swift index 491015e..8a697fd 100644 --- a/Sources/TableRow.swift +++ b/Sources/TableRow.swift @@ -63,12 +63,7 @@ open class TableRow: Row where CellType: UITableView (cell as? CellType)?.configure(with: item) } - - open func height(for cell: UITableViewCell) -> CGFloat { - - return (cell as? CellType)?.height(for: item) ?? UITableView.automaticDimension - } - + // MARK: - RowActionable - open func invoke(action: TableRowActionType, cell: UITableViewCell?, path: IndexPath, userInfo: [AnyHashable: Any]? = nil) -> Any? { diff --git a/TableKit.xcodeproj/project.pbxproj b/TableKit.xcodeproj/project.pbxproj index 068fb5f..ff64415 100644 --- a/TableKit.xcodeproj/project.pbxproj +++ b/TableKit.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */; }; 3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78721BE9EB2001DF9E7 /* Expandable.swift */; }; 3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */; }; - 320C5280218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */; }; 32BDFE9F21C167F400D0BBB4 /* LayoutType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */; }; 50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; }; 50E858581DB153F500A9AA55 /* TableKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E858571DB153F500A9AA55 /* TableKit.swift */; }; @@ -42,7 +41,6 @@ 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+Extensions.swift"; sourceTree = ""; }; 3201E78721BE9EB2001DF9E7 /* Expandable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Expandable.swift; sourceTree = ""; }; 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewModel.swift; sourceTree = ""; }; - 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccurateCellHeightCalculator.swift; sourceTree = ""; }; 32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutType.swift; sourceTree = ""; }; 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = ""; }; 50E858571DB153F500A9AA55 /* TableKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKit.swift; sourceTree = ""; }; @@ -102,7 +100,6 @@ DA9EA7A51D0EC2B90021F650 /* Sources */ = { isa = PBXGroup; children = ( - 320C527F218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift */, DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */, 3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */, DA9EA7A81D0EC2C90021F650 /* Operators.swift */, @@ -253,7 +250,6 @@ DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */, DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */, 3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */, - 320C5280218EB9A7004EAD1C /* AccurateCellHeightCalculator.swift in Sources */, DA9EA7B71D0EC2C90021F650 /* TableSection.swift in Sources */, DA9EA7B01D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift in Sources */, 3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */, From 65cf31717b6924af4c8c8e63f5eb903fe6a0d464 Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Wed, 9 Jan 2019 16:08:25 +0300 Subject: [PATCH 7/8] Remove deprecated attribute for estimatedHeight --- Sources/ConfigurableCell.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/ConfigurableCell.swift b/Sources/ConfigurableCell.swift index b7d9464..02817a7 100644 --- a/Sources/ConfigurableCell.swift +++ b/Sources/ConfigurableCell.swift @@ -26,7 +26,6 @@ public protocol ConfigurableCell { static var reuseIdentifier: String { get } - @available(*, deprecated, message: "For static cells use defaultHeight, height of self-sized cells will be calculated automatically") static var estimatedHeight: CGFloat? { get } static var defaultHeight: CGFloat? { get } From a768352b47a5ddf24ab00ff3ae6a511804c64a2a Mon Sep 17 00:00:00 2001 From: Ivan Zinovyev Date: Wed, 9 Jan 2019 18:59:29 +0300 Subject: [PATCH 8/8] Some refactoring --- Sources/ExpandableCellHeightCalculator.swift | 2 +- Sources/UITableViewCell+Extensions.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/ExpandableCellHeightCalculator.swift b/Sources/ExpandableCellHeightCalculator.swift index 08bbecf..351d342 100644 --- a/Sources/ExpandableCellHeightCalculator.swift +++ b/Sources/ExpandableCellHeightCalculator.swift @@ -2,7 +2,7 @@ import UIKit public final class ExpandableCellHeightCalculator: RowHeightCalculator { - private(set) weak var tableView: UITableView? + private weak var tableView: UITableView? private var prototypes = [String: UITableViewCell]() diff --git a/Sources/UITableViewCell+Extensions.swift b/Sources/UITableViewCell+Extensions.swift index b65055a..6709bf4 100644 --- a/Sources/UITableViewCell+Extensions.swift +++ b/Sources/UITableViewCell+Extensions.swift @@ -2,7 +2,7 @@ import UIKit extension UITableViewCell { - public var tableView: UITableView? { + var tableView: UITableView? { var view = superview while view != nil && !(view is UITableView) { @@ -12,7 +12,7 @@ extension UITableViewCell { return view as? UITableView } - public var indexPath: IndexPath? { + var indexPath: IndexPath? { guard let indexPath = tableView?.indexPath(for: self) else { return nil }