RxSwift 5.RxDataSources

文章目录
  1. 1. Table 和 Collection View data sources
  2. 2. 特性
  3. 3. 为什么
  4. 4. 怎么用
  5. 5. 数据源动画
  6. 6. 需要
  7. 7. 安装
    1. 7.1. CocoaPods
    2. 7.2. Carthage

原文: RxDataSources

Table 和 Collection View data sources

特性

  • [x] O(N)计算差异的算法
    • 该算法假设所有 sections 和 items 都是唯一的,因此没有二义性
    • 如果有歧义,在非动画刷新时自动回退
  • [x] 他使用其他启发式方法以将最少数量的命令发送到分段视图
    • 即使运行时间是线性的,发送命令的首选数量通常也比线性少
    • 最好(并且有可能)将更改数量限制为较小的数量,并且如果更改数量朝线性方向增长,则只需进行正常的reload即可
  • [x] 支持扩展你的 item 和 section 结构
    • 只需使用 IdentifiableTypeEquatable 扩展你的 item,并使用 AnimatableSectionModelType 扩展 section
  • [x] 支持 section 和 item 的两级分层动画的所有组合
    • Section 动画: Insert, Delete, Mov
    • Item 动画: Insert, Delete, Move, Reload (如果旧值不等于新值)
  • [x] 可配置动画类型对于 Insert, Reload and Delete (Automatic, Fade, …)
  • [x] 示例 app
  • [x] 随机压力测试(eg app)
  • [x] 支持开箱即用的编辑(eg app)
  • [x] 同 UITableView 和 UICollectionView 一起工作

为什么

编写 table 和 collection View 数据源很繁琐。对于最简单的情况,需要实现大量的委托方法。

RxSwift 通过简单的数据绑定机制有助于减轻一些负担:

  1. 把你的数据转化成可见听序列 Observable
  2. 使用下面方法把数据绑定到 tableView/collectionView 上
    • rx.items(dataSource:protocol<RxTableViewDataSourceType, UITableViewDataSource>)
    • rx.items(cellIdentifier:String)
    • rx.items(cellIdentifier:String:Cell.Type:_: )
    • rx.items(:: )
1
2
3
4
5
6
let data = Observable<[String]>.just(["first element", "second element", "third element"])

data.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { index, model, cell in
cell.textLabel?.text = model
}
.disposed(by: disposeBag)

这适用于简单数据集,但不适用于需要将复杂数据集与多个section 绑定或在添加/修改/删除item 时需要执行动画的情况。

这些正是RxDataSources帮助解决的用例。

使用RxDataSources,写起来非常容易

1
2
3
4
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, Int>>(configureCell: configureCell)
Observable.just([SectionModel(model: "title", items: [1, 2, 3])])
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)

-

怎么用

给定以下自定义数据结构:

1
2
3
4
5
struct CustomData {
var anInt: Int
var aString: String
var aCGPoint: CGPoint
}
  1. 首先使用遵循 SectionModelType 协议的结构定义你的section:
    • 定义 item 类型别名:等于该 section 将包含的 item 类型
    • 声明一个 items 属性:Item 类型数组
1
2
3
4
5
6
7
8
9
10
11
12
struct SectionOfCustomData {
var header: String
var items: [Item]
}
extension SectionOfCustomData: SectionModelType {
typealias Item = CustomData

init(original: SectionOfCustomData, items: [Item]) {
self = original
self.items = items
}
}
  1. 创建一个dataSource对象,并将其传递给 SectionOfCustomData 类型:
1
2
3
4
5
6
7
8
9
10
11
let dataSource = RxTableViewSectionedAnimatedDataSource<MySection>(
configureCell: { ds, tv, _, item in
let cell = tv.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = "Item \(item)"

return cell
},
titleForHeaderInSection: { ds, index in
return ds.sectionModels[index].header
}
)
  1. 根据需要在dataSource上自定义闭包:
    • titleForHeaderInSection
    • titleForFooterInSection
    • etc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dataSource.titleForHeaderInSection = { dataSource, index in
return dataSource.sectionModels[index].header
}

dataSource.titleForFooterInSection = { dataSource, indexPath in
return dataSource.sectionModels[index].footer
}

dataSource.canEditRowAtIndexPath = { dataSource, indexPath in
return true
}

dataSource.canMoveRowAtIndexPath = { dataSource, indexPath in
return true
}
  1. 将实际数据定义为 CustomData 对象的 Observable序列,并将其绑定到tableView
1
2
3
4
5
6
7
8
let sections = [
SectionOfCustomData(header: "First section", items: [CustomData(anInt: 0, aString: "zero", aCGPoint: CGPoint.zero), CustomData(anInt: 1, aString: "one", aCGPoint: CGPoint(x: 1, y: 1)) ]),
SectionOfCustomData(header: "Second section", items: [CustomData(anInt: 2, aString: "two", aCGPoint: CGPoint(x: 2, y: 2)), CustomData(anInt: 3, aString: "three", aCGPoint: CGPoint(x: 3, y: 3)) ])
]

Observable.just(sections)
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)

数据源动画

RxDataSources 提供了两种特殊的数据源类型,它们可以自动处理绑定数据源中的动画变化:RxTableViewSectionedAnimatedDataSourceRxCollectionViewSectionedAnimatedDataSource

要使用两个动画数据源之一,你必须在上述概述的基础上采取一些额外的步骤:

  • SectionOfCustomData需要遵守 AnimatableSectionModelType 协议
  • 数据模型必须符合
    • IdentifiableType:IdentifiableType 协议提供的 identity 必须是表示模型实例的不可变标识符(identifier)。例如,对于 Car 模型,你可能要使用 Car 的plateNumber 作为其标识。
    • Equatable:遵从 Equatable 协议 有助于RxDataSources确定哪些 cell 已更改,因此它只能为这些特定 cell 设置动画。这意味着,更改Car模型的任何属性都会触发该 cell 的动画重新加载。

需要

Xcode 10.2

Swift 5.0

For Swift 4.x version please use versions 3.0.0 … 3.1.0 For Swift 3.x version please use versions 1.0 … 2.0.2 For Swift 2.3 version please use versions 0.1 … 0.9

安装

CocoaPods

Podfile

pod ‘RxDataSources’, ‘~> 4.0’

Carthage

Cartfile

github “RxSwiftCommunity/RxDataSources” ~> 4.0