持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
前言
又来撸RXSwift了
今天来操作一下,使用RXSwift来撸一个collectionview
如果还没看过之前的文章,可以跳转到这里:使用RXSwift撸一个MVVM架构的Tableview
今天这个collectionview
,还是先从最基本的一个section
开始。下一篇咱们在来点复杂的。
还是先声明 咱们使用的版本是
pod 'RxSwift', '~> 5.0'
pod 'RxCocoa', '~> 5.0'
版本比较新,对应以前的版本,RXSwift有语法上的变化,注意
正文
咱们使用的是MVVM方式构建代码 先看目录
第一步: 模型(Model)
我们在Model文件夹下创建一个Product
模型
import Foundation
struct Product {
let name: String// 名称
let price: String// 价格
}
第二步: 视图模型(ViewModel)
咱们在 ViewModel 文件夹下创建一个 GoodsViewModel
它的作用就是是 View 和 Model 之间的连接器,它可以将获取到的数据传输到 ViewController。
class GoodsViewModel {
let items = PublishSubject<[Goods]>()
func fetchGoodsList() {
// 在这里可以做网络请求
// 咱们就直接用假数据
let goodsArray = [
Goods( name: "MacBook", price: "100"),
Goods( name: "iPhone Xs", price: "100"),
Goods( name: "iWatch", price: "100"),
Goods( name: "iPad", price: "100"),
Goods( name: "iPhone X", price: "100")
]
items.onNext(goodsArray)
items.onCompleted()
}
}
第三步 视图(view)
咱们在view文件夹下创建GoodsViewController
继承自 UIViewController
在GoodsViewController
中 咱们来编写RXSwift的核心代码。
首先呢,要定义两个属性
private let bag = DisposeBag()
private let viewModel = GoodsViewModel()
bag
: 是和生命周期相关
viewModel
: 就是视图模型拉
然后在viewDidLoad
设置collectionview
override func viewDidLoad() {
super.viewDidLoad()
// 定义布局方式以及单元格大小
let flowLayout = UICollectionViewFlowLayout()
flowLayout.sectionInset = UIEdgeInsets.init(top: 0, left: 5, bottom: 0, right: 5)
flowLayout.itemSize = CGSize(width: (SCREEN_WIDTH-50)/3.0, height: 70)
// 创建集合视图
self.collectionView = UICollectionView(frame: self.view.frame,
collectionViewLayout: flowLayout)
self.collectionView.backgroundColor = UIColor.white
self.view.addSubview(self.collectionView!)
bindView()
}
这里 collectionview
的初始化和原来的基本上没什么差别, 咱们来看 bindView()
里是如何实现的。
private func bindView() {
// 创建一个重用的单元格
collectionView.register(MyCollectionViewCell.self,
forCellWithReuseIdentifier: "Cell")
// 绑定cell
viewModel.items.bind(to: collectionView.rx.items(cellIdentifier: "cellId", cellType: MyCollectionViewCell.self)) { (row,item,cell) in
cell.label.text = "\(row):\(element)"
}.disposed(by: bag)
// 获取indexpath
collectionView.rx.itemSelected.subscribe(onNext: { indexPath in print("选中项的indexPath为:\(indexPath)") }).disposed(by: disposeBag)
// 获取选中项的内容
collectionView.rx.modelSelected(String.self).subscribe(onNext: { item in
print("选中项的标题为:\(item)")
}).disposed(by: disposeBag)
// 模拟请求
viewModel.fetchProductList()
}
第一步:先注册cell 。
第二步:将 viewModel.items 绑定到 collectionview 的 cell上,在RXSwift给的闭包中,进行 cell 的赋值操作,这样就省去了设置Datasource。
第三步:在RXSwift中 获取indexpath
和item
是分别两个函数 itemSelected
h和modelSelected
不像原生中,一个函数就可以完成(这也是一个比较麻烦的事)。但是RXSwift还有一个zip
的方法。可以将两个合并(是不是很神奇),咱们来看看
Observable
.zip(collectionView.rx.itemDeselected, collectionView.rx.modelDeselected(String.self))
.bind { [weak self] indexPath, item in
print("被取消选中项的indexPath为:\(indexPath)")
print("被取消选中项的的标题为:\(item)")
}
.disposed(by: disposeBag)
这样,就实现原来的didselect的方法了。
第四步:还是假装请求。
到这里,一个使用MVVM架构的collectionview就完成了(cell按需可以自己定义,这里就不写了)。其实写法和tableview差不多,手熟尔。
结语
总体来说,使用RXSwift来做collectionview也是比较迅速的。适用于快速布局,但是在大多时候,可能没有机会去用到,这就需要大家可以再重构或者一开始的时候就去考虑使用。这样才有使用记忆。