Swift项目相关

swift ~ MVVM之UITableView绑定

2018-06-14  本文已影响193人  RudyHao

本篇讲解一行代码搞定UITableView绑定

final class ViewController: UIViewController{
    //数据源
    var data = []

    /**
     * 创建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()
        /**
     * 创建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实现ReactiveView协议《可读源码&改造源码》
        self.tbAdapter =  TableViewBindingAdapter<Model>(
        tableView: self.tableView,
        sourceSignal: (viewModel.dataSource),
        nibName: TableViewCell.getClassName())
    }
}

怎么样,是不是精神气爽?哈哈,感谢Rx给开发带来的便捷...
基本思路: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: 数据源
    ///   - 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")
    }
}

持续分享源码待续...

上一篇下一篇

猜你喜欢

热点阅读