Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Bandd-k
Last active May 13, 2019 13:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bandd-k/ea0bd7fe11e8d4e5ac32f8388a7a6a4c to your computer and use it in GitHub Desktop.
Save Bandd-k/ea0bd7fe11e8d4e5ac32f8388a7a6a4c to your computer and use it in GitHub Desktop.
class SectionModel {
var items: [Any] {
didSet {
print("aaa")
}
}
var numberOfItems: Int { return items.count }
init(items: [Any]) {
self.items = items
}
func item(at index: Int) -> Any {
return items[index]
}
private func update(old: [AnyObject], new: [AnyObject]) {
// calculate diff
}
}
class DenisTableView: UITableView {
// : UITableViewController
var sections: [SectionModel] = [] {
didSet {
self.reloadData()
}
}
var configurators: [String: AnyCellConfigurator] = [:]
var cachedCellHeights: [IndexPath: CGFloat] = [:]
weak var owner: DenisTableViewOwner?
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
self.delegate = self
self.dataSource = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func register(configurator: AnyCellConfigurator) {
configurators[configurator.reuseID] = configurator // check if already exists and throw erro
self.register(configurator.cellClass, forCellReuseIdentifier: configurator.reuseID)
}
func objects(for indexPath: IndexPath) -> (item: Any, configurator: AnyCellConfigurator) {
let item = sections[indexPath.section].item(at: indexPath.row)
let thisType: Any.Type = type(of: item)
let reuseID = String(describing: thisType)
let configurator = configurators[reuseID]! // no config, throw an error
return (item, configurator)
}
}
extension DenisTableView: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].numberOfItems
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let (item, configurator) = objects(for: indexPath)
let cell = dequeueReusableCell(withIdentifier: configurator.reuseID)! // guard as well
configurator.configureAnyCell(cell, item, indexPath)
return cell
}
}
extension DenisTableView: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// cachedCellHeights
let (item, configurator) = objects(for: indexPath)
return configurator.heightForAnyItem?(item) ?? 30 // add autoCalculationBlock
}
// func autoCalculateBlockHeightFunc(for configurator: CellConfigurator<UITableViewCell, AnyObject>) -> (AnyObject) -> CGFloat {
// let cell = configurator.oneCell
// let heightBlock: (AnyObject) -> CGFloat = { item -> CGFloat in
// configurator.configureCell(cell, item, IndexPath(row: 0, section: 0))
// cell.updateConstraints()
// cell.bounds = CGRect(origin: .zero, size: CGSize(width: self.bounds.width, height: cell.bounds.height))
// cell.setNeedsLayout()
// cell.layoutIfNeeded()
// let height = cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
// return height
// }
// return heightBlock
// }
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.owner?.tableView?(self, willDisplayCell: cell, at: indexPath)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// maybe call action automatically
self.owner?.tableView?(self, didSelectRow: sections[indexPath.section].item(at: indexPath.row), at: indexPath)
}
}
struct CellConfigurator<Cell: UITableViewCell, Item: Any> {
var cellClass: AnyClass { return Cell.self }
var reuseID: String { return String(describing: Item.self) }
var heightForItem: ((Item) -> CGFloat)?
let configureCell: (Cell, Item, IndexPath?) -> ()
}
extension CellConfigurator: AnyCellConfigurator {
// do not call directly
var configureAnyCell: (UITableViewCell, Any, IndexPath?) -> () {
return { [configureCell] cell, item, indexPath in
configureCell(cell as! Cell, item as! Item, indexPath)
}
}
var heightForAnyItem: ((Any) -> CGFloat)? {
return heightForItem.map { height in { item in height(item as! Item) } }
}
}
protocol AnyCellConfigurator {
var cellClass: AnyClass { get }
var reuseID: String { get }
var heightForAnyItem: ((Any) -> CGFloat)? { get }
var configureAnyCell: (UITableViewCell, Any, IndexPath?) -> () { get }
}
@objc
protocol DenisTableViewOwner: AnyObject {
@objc optional func tableView(_ tableView: DenisTableView, didSelectRow model: Any, at indexPath: IndexPath)
@objc optional func tableView(_ tableView: DenisTableView, willDisplayCell cell: UITableViewCell, at indexPath: IndexPath)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment