UITableView的使用

  • 單個分區(qū)的表格

//創(chuàng)建表格視圖
self.tableView = UITableView(frame: self.view.frame, style:.plain)
//創(chuàng)建一個重用的單元格
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
    // 取消選中,這句代碼執(zhí)行后不會觸發(fā) 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
    // 取消選中,這句代碼執(zhí)行后不會觸發(fā) 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
        // 取消選中,這句代碼執(zhí)行后不會觸發(fā) 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為編輯狀態(tài),并實現代理方法,顯示左邊對應的按鈕

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 是單分區(qū)還是多分區(qū),在使用 RxDataSources 的過程中,都需要返回一個 section 的數組。

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

//設置分區(qū)頭標題
dataSource.titleForHeaderInSection = { ds, index in
    return ds.sectionModels[index].model
}
        
//設置分區(qū)尾標題
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)
         
//創(chuàng)建數據源
let dataSource = RxTableViewSectionedReloadDataSource
    <SectionModel<String, Int>>(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<String, Int>])
            -> Observable<[SectionModel<String, Int>]> {
                return self.searchBar.rx.text.orEmpty
                    //.debounce(0.5, scheduler: MainScheduler.instance) //只有間隔超過0.5秒才發(fā)送
                    .flatMapLatest{
                        query -> Observable<[SectionModel<String, Int>]> in
                        print("正在篩選數據(條件為:\(query))")
                        //輸入條件為空,則直接返回原始數據
                        if query.isEmpty{
                            return Observable.just(data)
                        }
                            //輸入條件為不空,則只返回包含有該文字的數據
                        else{
                            var newData:[SectionModel<String, Int>] = []
                            for sectionModel in data {
                                let items = sectionModel.items.filter{ "\($0)".contains(query) }
                                newData.append(SectionModel(model: sectionModel.model, items: items))
                            }
                            return Observable.just(newData)
                        }
                }
        }
  • 不同類型的單元格混用

//創(chuàng)建數據源
let dataSource = RxTableViewSectionedReloadDataSource<MySection>(
    //設置單元格
    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
                }
            },
            //設置分區(qū)頭標題
            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:樣式修改)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網絡請求組件 FMDB本地數據庫組件 SD...
    陽明AI閱讀 16,211評論 3 119
  • 這個星期六,我又回媽媽的老家了。 回到爺爺家后,我發(fā)現四爺和舅舅都在爺爺家,他們正在蓋一個豬圈...
    在水一方_7228閱讀 93評論 0 0
  • A區(qū): 人生目標關鍵詞:事業(yè)/健康/親子/家庭/人際/提升/時間管理 2018年目標:學習瑜伽知識,及開始習練瑜伽...
    藍天白云_d7bd閱讀 105評論 0 0
  • 瑞達利奧的其中一個原則:考察影響你的那些事物的規(guī)律,從而理解其背后的因果關系,學習有效應對這些失誤的原則。 他覺得...
    我是個秀閱讀 743評論 0 0
  • 2015-04-01 今天天氣不怎么好,下雨了。 4月的第一天,便在雨的迎接中來臨了。滿世界的水花,嘩啦的喧囂,都...
    逗比丁閱讀 251評論 0 1

友情鏈接更多精彩內容