UITableView的使用

  • 单个分区的表格

//创建表格视图
self.tableView = UITableView(frame: self.view.frame, style:.plain)
//创建一个重用的单元格
self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView!)
         
//初始化数据
let items = Observable.just([
    "文本输入框的用法",
    "开关按钮的用法",
    "进度条的用法",
    "文本标签的用法",
    ])
         
//设置单元格数据(其实就是对 cellForRowAt 的封装)
items
    .bind(to: tableView.rx.items) { (tableView, row, element) in
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
        cell.textLabel?.text = "\(row):\(element)"
        return cell
        }
      .disposed(by: disposeBag)

// 或者拆开写为
let bibao = items.bind(to: (tableView?.rx.items(cellIdentifier: "Cell", cellType: UITableViewCell.self))!)
bibao {
    (row, element, cell) in
    cell.textLabel?.text = "\(row):\(element)"
}.disposed(by: disposeBag)
  • 单元格选中事件响应

//获取选中项的索引
tableView.rx.itemSelected.subscribe(onNext: { indexPath in
    // 取消选中,这句代码执行后不会触发 tableView.rx.itemDeselected和tableView.rx.modelDeselected
    self.tableView!.deselectRow(at: indexPath, animated: false)    

    print("选中项的indexPath为:\(indexPath)")
}).disposed(by: disposeBag)
 
//获取选中项的内容
tableView.rx.modelSelected(String.self).subscribe(onNext: { item in
    print("选中项的标题为:\(item)")
}).disposed(by: disposeBag)

// 或者
//获取选中项的索引
tableView.rx.itemSelected.subscribe(onNext: { [weak self] indexPath in
    // 取消选中,这句代码执行后不会触发 tableView.rx.itemDeselected和tableView.rx.modelDeselected
    self.tableView!.deselectRow(at: indexPath, animated: false)    

    self?.showMessage("选中项的indexPath为:\(indexPath)")
}).disposed(by: disposeBag)
 
//获取选中项的内容
tableView.rx.modelSelected(String.self).subscribe(onNext: {[weak self] item in
    self?.showMessage("选中项的标题为:\(item)")
}).disposed(by: disposeBag)

// 合并
Observable.zip(tableView.rx.itemSelected, tableView.rx.modelSelected(String.self))
    .bind { [weak self] indexPath, item in
        // 取消选中,这句代码执行后不会触发 tableView.rx.itemDeselected和tableView.rx.modelDeselected
        self.tableView!.deselectRow(at: indexPath, animated: false) 

        self?.showMessage("选中项的indexPath为:\(indexPath)")
        self?.showMessage("选中项的标题为:\(item)")
    }
    .disposed(by: disposeBag)
  • 单元格取消选中事件响应

//获取被取消选中项的索引
tableView.rx.itemDeselected.subscribe(onNext: { [weak self] indexPath in
    self?.showMessage("被取消选中项的indexPath为:\(indexPath)")
}).disposed(by: disposeBag)
 
//获取被取消选中项的内容
tableView.rx.modelDeselected(String.self).subscribe(onNext: {[weak self] item in
    self?.showMessage("被取消选中项的的标题为:\(item)")
}).disposed(by: disposeBag)

// 合并
Observable.zip(tableView.rx.itemDeselected, tableView.rx.modelDeselected(String.self))
    .bind { [weak self] indexPath, item in
        self?.showMessage("被取消选中项的indexPath为:\(indexPath)")
        self?.showMessage("被取消选中项的的标题为:\(item)")
    }
    .disposed(by: disposeBag)
  • 编辑单元格

编辑单元格时,除了删除直接实现下面代码,可以实现左滑删除功能,但不会在左边显示删除按钮;其他的操作,都必须使tableView为编辑状态,并实现代理方法,显示左边对应的按钮

self.tableView!.isEditing = true

func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
        return .insert
    }
  • 单元格删除事件响应
//获取删除项的索引
tableView.rx.itemDeleted.subscribe(onNext: { [weak self] indexPath in
    self?.showMessage("删除项的indexPath为:\(indexPath)")
}).disposed(by: disposeBag)

//获取删除项的内容
tableView.rx.modelDeleted(String.self).subscribe(onNext: {[weak self] item in
    self?.showMessage("删除项的的标题为:\(item)")
}).disposed(by: disposeBag)
  • 单元格移动事件响应
//获取移动项的索引
tableView.rx.itemMoved.subscribe(onNext: { [weak self]
    sourceIndexPath, destinationIndexPath in
    self?.showMessage("移动项原来的indexPath为:\(sourceIndexPath)")
    self?.showMessage("移动项现在的indexPath为:\(destinationIndexPath)")
}).disposed(by: disposeBag)
  • 单元格插入事件响应
//获取插入项的索引
tableView.rx.itemInserted.subscribe(onNext: { [weak self] indexPath in
    self?.showMessage("插入项的indexPath为:\(indexPath)")
}).disposed(by: disposeBag)
  • 单元格尾部附件(图标)点击事件响应
//获取点击的尾部图标的索引
tableView.rx.itemAccessoryButtonTapped.subscribe(onNext: { [weak self] indexPath in
    self?.showMessage("尾部项的indexPath为:\(indexPath)")
}).disposed(by: disposeBag)
  • RxDataSources

如果我们的 tableview 需要显示多个 section、或者更加复杂的编辑功能时,可以借助 RxDataSource 这个第三方库帮我们完成。
RxDataSource 的本质就是使用 RxSwift 对 UITableView 和 UICollectionView 的数据源做了一层包装。使用它可以大大减少我们的工作量

pod 'RxDataSources'

注意:RxDataSources 是以 section 来做为数据结构的。所以不管我们的 tableView 是单分区还是多分区,在使用 RxDataSources 的过程中,都需要返回一个 section 的数组。

//初始化数据
let items = Observable.just([
            SectionModel(model: "基本控件", items: [
                "UILable的用法",
                "UIText的用法",
                "UIButton的用法"
                ]),
            SectionModel(model: "高级控件", items: [
                "UITableView的用法",
                "UICollectionViews的用法"
                ])
            ])
         
//创建数据源
let dataSource = RxTableViewSectionedReloadDataSource
    >(configureCell: {
        (dataSource, tv, indexPath, element) in
            let cell = tv.dequeueReusableCell(withIdentifier: "Cell")!
            cell.textLabel?.text = "\(indexPath.row):\(element)"
    })

//设置分区头标题
dataSource.titleForHeaderInSection = { ds, index in
    return ds.sectionModels[index].model
}
        
//设置分区尾标题
dataSource.titleForFooterInSection = { ds, index in
    return "footer"
}
         
//绑定单元格数据
items
    .bind(to: tableView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag)
  • 数据刷新

//随机的表格数据
let randomResult = refreshButton.rx.tap.asObservable()
            .startWith(()) //加这个为了让一开始就能自动请求一次数据
            .flatMapLatest{
                // 取消请求takeUntil
                self.getRandomResult().takeUntil(self.cancelButton.rx.tap)
            }
            .flatMap(filterResult) //筛选数据
            .share(replay: 1)
         
//创建数据源
let dataSource = RxTableViewSectionedReloadDataSource
    >(configureCell: {
        (dataSource, tv, indexPath, element) in
        let cell = tv.dequeueReusableCell(withIdentifier: "Cell")!
        cell.textLabel?.text = "条目\(indexPath.row):\(element)"
        return cell
    })
         
//绑定单元格数据
randomResult
    .bind(to: tableView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag)
//过滤数据
func filterResult(data:[SectionModel])
            -> Observable<[SectionModel]> {
                return self.searchBar.rx.text.orEmpty
                    //.debounce(0.5, scheduler: MainScheduler.instance) //只有间隔超过0.5秒才发送
                    .flatMapLatest{
                        query -> Observable<[SectionModel]> in
                        print("正在筛选数据(条件为:\(query))")
                        //输入条件为空,则直接返回原始数据
                        if query.isEmpty{
                            return Observable.just(data)
                        }
                            //输入条件为不空,则只返回包含有该文字的数据
                        else{
                            var newData:[SectionModel] = []
                            for sectionModel in data {
                                let items = sectionModel.items.filter{ "\($0)".contains(query) }
                                newData.append(SectionModel(model: sectionModel.model, items: items))
                            }
                            return Observable.just(newData)
                        }
                }
        }
  • 不同类型的单元格混用

//创建数据源
let dataSource = RxTableViewSectionedReloadDataSource(
    //设置单元格
    configureCell: { dataSource, tableView, indexPath, item in
        switch dataSource[indexPath] {
            case let .TitleImageSectionItem(title, image):
                let cell = tableView.dequeueReusableCell(withIdentifier: "titleImageCell",
                                                             for: indexPath)
                    (cell.viewWithTag(1) as! UILabel).text = title
                    (cell.viewWithTag(2) as! UIImageView).image = image
                    return cell
                     
            case let .TitleSwitchSectionItem(title, enabled):
                let cell = tableView.dequeueReusableCell(withIdentifier: "titleSwitchCell",
                                                             for: indexPath)
                    (cell.viewWithTag(1) as! UILabel).text = title
                    (cell.viewWithTag(2) as! UISwitch).isOn = enabled
                    return cell
                }
            },
            //设置分区头标题
            titleForHeaderInSection: { ds, index in
                return ds.sectionModels[index].header
            }
        )
  • 样式修改

修改单元格高度、设置组头组尾,这些操作RxSwift没有封装,所以需要用原始的代理方法来实现

//设置代理
tableView.rx.setDelegate(self)
            .disposed(by: disposeBag)

参考文章:Swift - RxSwift的使用详解30(UITableView的使用1:基本用法)
Swift - RxSwift的使用详解31(UITableView的使用2:RxDataSources)
Swift - RxSwift的使用详解32(UITableView的使用3:刷新表格数据)
Swift - RxSwift的使用详解33(UITableView的使用4:表格数据的搜索过滤)
Swift - RxSwift的使用详解34(UITableView的使用5:可编辑表格)
Swift - RxSwift的使用详解35(UITableView的使用6:不同类型的单元格混用)
Swift - RxSwift的使用详解36(UITableView的使用7:样式修改)

你可能感兴趣的:(UITableView的使用)