Created
October 6, 2017 13:54
-
-
Save pavankataria/193a929de8525ac5744afe28158516c5 to your computer and use it in GitHub Desktop.
Injecting View into Generic TableViewCell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import UIKit | |
public protocol CellRepresentable { | |
static func registerCell(tableView: UITableView) | |
func dequeueCell(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell | |
func cellSelected(_ indexPath: IndexPath) | |
} | |
//MARK: - Default Implementation | |
class TitleView: UIView { | |
let label = UILabel() | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
configure() | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
configure() | |
} | |
private func configure() { | |
backgroundColor = .red | |
addSubview(label) | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
label.frame = bounds | |
} | |
} | |
extension TitleView { | |
func setup(_ viewModel: TitleViewCellViewModel){ | |
self.label.text = viewModel.title | |
} | |
} | |
class ButtonView: UIView { | |
let button = UIButton() | |
var didPressButtonEvent: (() -> Void)? | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
configure() | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
configure() | |
} | |
private func configure() { | |
backgroundColor = .green | |
button.addTarget(self, action: #selector(self.didPressButton), for: .touchUpInside) | |
button.backgroundColor = .cyan | |
addSubview(button) | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
button.frame = bounds | |
} | |
@objc func didPressButton(){ | |
self.didPressButtonEvent?() | |
} | |
} | |
extension ButtonView { | |
func setup(_ viewModel: ButtonViewCellViewModel){ | |
self.button.setTitle(viewModel.title, for: .normal) | |
self.didPressButtonEvent = viewModel.didPressEvent | |
} | |
} | |
class ButtonViewCellViewModel { | |
var title: String | |
var didPressEvent: (() -> Void)? | |
init(title: String, handler: (() -> Void)?){ | |
self.title = title | |
self.didPressEvent = handler | |
} | |
} | |
extension ButtonViewCellViewModel: CellRepresentable { | |
private struct Properties { | |
static let identifier = “CustomCellButtonView” | |
} | |
static func registerCell(tableView: UITableView) { | |
tableView.register(CustomCell<ButtonView>.self, forCellReuseIdentifier: Properties.identifier) | |
} | |
func dequeueCell(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell { | |
guard let cell = tableView.dequeueReusableCell(withIdentifier: Properties.identifier, for: indexPath) as? CustomCell<ButtonView> else { | |
fatalError() | |
} | |
cell.customView.setup(self) | |
return cell | |
} | |
func cellSelected(_ indexPath: IndexPath) { | |
} | |
} | |
//MARK: - TitleViewCellViewModel setup | |
class TitleViewCellViewModel { | |
let title: String | |
init(title: String){ | |
self.title = title | |
} | |
} | |
extension TitleViewCellViewModel: CellRepresentable { | |
private struct Properties { | |
static let identifier = “CustomCellTitleView” | |
} | |
static func registerCell(tableView: UITableView) { | |
tableView.register(CustomCell<TitleView>.self, forCellReuseIdentifier: Properties.identifier) | |
} | |
func dequeueCell(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell { | |
guard let cell = tableView.dequeueReusableCell(withIdentifier: Properties.identifier, for: indexPath) as? CustomCell<TitleView> else { | |
fatalError() | |
} | |
cell.customView.setup(self) | |
return cell | |
} | |
func cellSelected(_ indexPath: IndexPath) { | |
} | |
} | |
class CustomCell<View: UIView>: UITableViewCell { | |
let customView = View(frame: .zero) | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
contentView.addSubview(customView) | |
customView.frame = contentView.bounds | |
} | |
} | |
class VCViewModel { | |
let cellViewModelTypes: [CellRepresentable.Type] = [ | |
TitleViewCellViewModel.self, | |
ButtonViewCellViewModel.self | |
] | |
var cellViewModels = [CellRepresentable]() | |
init(){ | |
self.cellViewModels = self.createCellViewModels() | |
} | |
func createCellViewModels() -> [CellRepresentable] { | |
var cells = [CellRepresentable]() | |
let titleCellViewModel = TitleViewCellViewModel(title: “Fuck yeah”) | |
cells.append(titleCellViewModel) | |
let buttonCellViewModel = ButtonViewCellViewModel(title: “Click me”){ | |
print(“did press button”) | |
} | |
cells.append(buttonCellViewModel) | |
return cells | |
} | |
} | |
class VC: UIViewController, UITableViewDataSource, UITableViewDelegate { | |
private let tableView = UITableView() | |
private let vCViewModel = VCViewModel() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = .white | |
view.addSubview(tableView) | |
tableView.dataSource = self | |
tableView.delegate = self | |
vCViewModel.cellViewModelTypes.forEach { $0.registerCell(tableView: tableView) } | |
} | |
override func viewDidLayoutSubviews() { | |
super.viewDidLayoutSubviews() | |
tableView.frame = view.bounds | |
} | |
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
return self.vCViewModel.cellViewModels.count | |
} | |
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
return self.vCViewModel.cellViewModels[indexPath.row].dequeueCell(tableView: tableView, indexPath: indexPath) | |
} | |
} | |
import PlaygroundSupport | |
let vc = VC() | |
PlaygroundPage.current.liveView = vc |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment