-
單個分區(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:樣式修改)