本篇講解一行代碼搞定UITableView綁定
- 原來我們的UITableView可能是這樣的
final class ViewController: UIViewController{
//數(shù)據(jù)源
var data = []
/**
* 創(chuàng)建tableView
*/
lazy var tableView: UITableView! = {
let tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
tableView.register(nibWithCellClass: TableViewCell.self)
self.view.addSubview(tableView)
return tableView
}()
}
extension ViewController: UITableViewDelegate {
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 30
}
}
extension ViewController: UITableViewDataSource {
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withClass: SVW_PowerListTableViewCell.self)
if indexPath.row >= data.count {
fatalError("index over items court")
}
guard let item = data.item(at: indexPath.row) else {
fatalError("cell model is empty")
}
do {
try cell?.setLayoutModel(item)
} catch {
fatalError(error.localizedDescription)
}
return cell!
}
}
對洞渤,我們大多的UITableView都是長這樣子额各,而且一個app可能有很多這樣的代碼脏答;有了Rx就可以一行代碼搞定啦...請看碼:
- 改造后的代碼是這樣的:
final class ViewController: UIViewController{
var tbAdapter:TableViewBindingAdapter<Model>?
var viewModel = ViewModel()
/**
* 創(chuàng)建tableView
*/
lazy var tableView: UITableView! = {
let tableView = UITableView()
//??????請注意這三行不需要了
//tableView.delegate = self
//tableView.dataSource = self
//tableView.register(nibWithCellClass: TableViewCell.self)
self.view.addSubview(tableView)
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
//別看這么長驯用,實際就一行??
//同時需要TableViewCell實現(xiàn)ReactiveView協(xié)議《可讀源碼&改造源碼》
self.tbAdapter = TableViewBindingAdapter<Model>(
tableView: self.tableView,
sourceSignal: (viewModel.dataSource),
nibName: TableViewCell.getClassName())
}
}
怎么樣庶弃,是不是精神氣爽?哈哈尺碰,感謝Rx給開發(fā)帶來的便捷...
基本思路
:Android的ListView適配器模式
資料來源
:鏈接
思路拓展
:可能有同學會問我想在tableview添加更復雜的功能咋辦挣棕?so easy,重寫一個適合自己需要的adapter即可
TableViewBindingAdapter源代碼
//
// TableViewBindingAdapter.swift
// ReactiveSwiftFlickrSearch
//
// Created by Colin Eberhardt on 15/07/2014.
// Copyright (c) 2014 Colin Eberhardt. All rights reserved.
//
import Foundation
import UIKit
import RxSwift
import RxCocoa
protocol ReactiveView {
func getCellHeight<M>(model: M)->CGFloat
func bindViewModel<M>(model: M)
}
// a helper that makes it easier to bind to UITableView instances
// see: http://www.scottlogic.com/blog/2014/05/11/reactivecocoa-tableview-binding.html
class TableViewBindingAdapter<T>: NSObject, UITableViewDataSource, UITableViewDelegate {
//MARK: Properties
private var disposeBag = DisposeBag()
var delegate: UITableViewDelegate?
private let tableView: UITableView
private let templateCell: UITableViewCell
private let rowCommand: PublishSubject<AnyObject>?
private let cellCommand: PublishSubject<AnyObject>?
private let sectionView: UIView?
private var data: [T]
/// table adapter
///
/// - Parameters:
/// - tableView: tableview
/// - sourceSignal: 數(shù)據(jù)源
/// - nibName: tableviewcell xib
/// - rowCommand: 行點擊時間
/// - cellCommand: 行內按鈕點擊事件
/// - sectionView: table section
init(tableView: UITableView, sourceSignal: Observable<[T]?>, nibName: String, rowCommand: PublishSubject<AnyObject>? = nil,cellCommand: PublishSubject<AnyObject>? = nil, sectionView:UIView? = nil) {
self.tableView = tableView
self.data = []
self.rowCommand = rowCommand
self.cellCommand = cellCommand
self.sectionView = sectionView
let nib = UINib(nibName: nibName, bundle: nil)
// create an instance of the template cell and register with the table view
templateCell = nib.instantiate(withOwner: nil, options: nil)[0] as! UITableViewCell
tableView.register(nib, forCellReuseIdentifier: NSStringFromClass(templateCell.classForCoder))
super.init()
sourceSignal.subscribe(onNext: {[weak self] (dic) in
if dic != nil{
self?.data = dic!
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
self?.tableView.reloadData()
})
}
}).disposed(by: self.disposeBag)
tableView.dataSource = self
tableView.delegate = self
}
//MARK: Private
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if (self.sectionView != nil) {
return self.sectionView!.height
}else{
return 0
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if (self.sectionView != nil) {
return self.sectionView
}else{
return nil
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item: T = data[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(templateCell.classForCoder))! as UITableViewCell
cell.event = self.cellCommand
if let reactiveView = cell as? ReactiveView {
reactiveView.bindViewModel(model: item)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(templateCell.classForCoder))! as UITableViewCell
let item: T = data[indexPath.row]
if let reactiveView = cell as? ReactiveView {
return reactiveView.getCellHeight(model: item)
}
else{
return templateCell.frame.size.height
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if rowCommand != nil {
rowCommand?.onNext(data[indexPath.row] as AnyObject)
}
tableView.deselectRow(at: indexPath, animated: true)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if self.delegate?.responds(to: #selector(UIScrollViewDelegate.scrollViewDidScroll(_:))) == true {
self.delegate?.scrollViewDidScroll?(scrollView);
}
}
deinit{
print("******************" + String(describing: self)+"******************deinit")
}
}
持續(xù)分享源碼待續(xù)...