RxSwift之UI控件UICollectionView扩展的使用

Posted Forever_wj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RxSwift之UI控件UICollectionView扩展的使用相关的知识,希望对你有一定的参考价值。

一、基本用法

① 单个分区的集合视图

  • 效果如下:

  • 示例代码:
// 定义布局方式以及单元格大小
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.collectionView.register(MyCollectionViewCell.self,
                             forCellWithReuseIdentifier: "Cell")
self.view.addSubview(self.collectionView!)
 
// 初始化数据
let items = Observable.just([
    "Swift",
    "php",
    "Ruby",
    "Java",
    "C++",
    ])
 
// 设置单元格数据(其实就是对 cellForItemAt 的封装)
items
    .bind(to: collectionView.rx.items) { (collectionView, row, element) in
        let indexPath = IndexPath(row: row, section: 0)
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",
                                        for: indexPath) as! MyCollectionViewCell
        cell.label.text = "\\(row)\\(element)"
        return cell
    }
    .disposed(by: disposeBag)

② 单元格选中事件响应

  • 如下所示,当点击某个单元格时将其索引位置,以及对应的标题打印出来:
选中项的indexPath为:[0, 0]
选中项的标题为:Swift
  • 如果业务代码直接放在响应方法内部,可以如下实现:
// 获取选中项的索引
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)
  • 也可以在响应中调用外部的方法实现:
// 获取选中项的索引
collectionView.rx.itemSelected.subscribe(onNext: { [weak self] indexPath in
	print("选中项的indexPath为:\\(indexPath)")
}).disposed(by: disposeBag)
 
// 获取选中项的内容
collectionView.rx.modelSelected(String.self).subscribe(onNext: {[weak self] item in
	print("选中项的标题为:\\(item)")
}).disposed(by: disposeBag)
  • 如果想要同时获取选中项的索引以及内容,可以如下实现:
Observable.zip(collectionView.rx.itemSelected, collectionView.rx.modelSelected(String.self))
    .bind { [weak self] indexPath, item in
        print("选中项的indexPath为:\\(indexPath)")
        print("选中项的标题为:\\(item)")
    }
    .disposed(by: disposeBag)

③ 单元格取消选中事件响应

被取消选中项的indexPath为:[0, 4]
被取消选中项的的标题为:C++
  • 可以分别获取被取消项的索引及内容:
// 获取被取消选中项的索引
collectionView.rx.itemDeselected.subscribe(onNext: { [weak self] indexPath in
	print("被取消选中项的indexPath为:\\(indexPath)")
}).disposed(by: disposeBag)
 
// 获取被取消选中项的内容
collectionView.rx.modelDeselected(String.self).subscribe(onNext: {[weak self] item in
	print("被取消选中项的的标题为:\\(item)")
}).disposed(by: disposeBag)
  • 也可以同时获取:
Observable
    .zip(collectionView.rx.itemDeselected, collectionView.rx.modelDeselected(String.self))
    .bind { [weak self] indexPath, item in
       	print("被取消选中项的indexPath为:\\(indexPath)")
		print("被取消选中项的的标题为:\\(item)")
    }
    .disposed(by: disposeBag)

④ 单元格高亮完成后的事件响应

高亮单元格的indexPath为:[0, 3]
  • 示例代码:
// 获取选中并高亮完成后的索引
collectionView.rx.itemHighlighted.subscribe(onNext: { indexPath in
    print("高亮单元格的indexPath为:\\(indexPath)")
}).disposed(by: disposeBag)

⑤ 高亮转成非高亮完成的事件响应

失去高亮的单元格的indexPath为:[0, 3]
  • 示例代码:
// 获取高亮转成非高亮完成后的索引
collectionView.rx.itemUnhighlighted.subscribe(onNext: { indexPath in
    print("失去高亮的单元格的indexPath为:\\(indexPath)")
}).disposed(by: disposeBag)

⑥ 单元格将要显示出来的事件响应

将要显示单元格indexPath为:[0, 0]
将要显示单元格cell为:<RxSwift.MyCollectionViewCell: 0x7fe0f1112490; baseClass = UICollectionViewCell; frame = (5 0; 126 70); layer = <CALayer: 0x6000006f1a40>>

将要显示单元格indexPath为:[0, 1]
将要显示单元格cell为:<RxSwift.MyCollectionViewCell: 0x7fe0f0706be0; baseClass = UICollectionViewCell; frame = (144 0; 126 70); layer = <CALayer: 0x6000006f6360>>

将要显示单元格indexPath为:[0, 2]
将要显示单元格cell为:<RxSwift.MyCollectionViewCell: 0x7fe0f1304420; baseClass = UICollectionViewCell; frame = (283 0; 126 70); layer = <CALayer: 0x6000006bd900>>

将要显示单元格indexPath为:[0, 3]
将要显示单元格cell为:<RxSwift.MyCollectionViewCell: 0x7fe0f1304e40; baseClass = UICollectionViewCell; frame = (5 80; 126 70); layer = <CALayer: 0x6000006bd960>>

将要显示单元格indexPath为:[0, 4]
将要显示单元格cell为:<RxSwift.MyCollectionViewCell: 0x7fe0f1113c50; baseClass = UICollectionViewCell; frame = (144 80; 126 70); layer = <CALayer: 0x6000006f18a0>>
  • 示例代码:
// 单元格将要显示出来的事件响应
collectionView.rx.willDisplayCell.subscribe(onNext: { cell, indexPath in
    print("将要显示单元格indexPath为:\\(indexPath)")
    print("将要显示单元格cell为:\\(cell)\\n")
}).disposed(by: disposeBag)

⑦ 分区头部或尾部将要显示出来的事件响应

// 分区头部、尾部将要显示出来的事件响应
collectionView.rx.willDisplaySupplementaryView.subscribe(onNext: { view, kind, indexPath in
	print("将要显示分区indexPath为:\\(indexPath)")
	print("将要显示的是头部还是尾部:\\(kind)")
	print("将要显示头部或尾部视图:\\(view)\\n")
}).disposed(by: disposeBag)

二、RxDataSources

① 单分区的 CollectionView

  • 如下所示,要实现如下效果:

  • 主视图控制器里的功能实现有如下两种写法:
    • 方式一:使用自带的 Section:
// 定义布局方式以及单元格大小
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.collectionView.register(MyCollectionViewCell.self,
                             forCellWithReuseIdentifier: "Cell")
self.view.addSubview(self.collectionView!)
 
// 初始化数据
let items = Observable.just([
    SectionModel(model: "", items: [
        "Swift",
        "PHP",
        "Python",
        "Java",
        "javascript",
        "C#"
        ])
    ])
 
// 创建数据源
let dataSource = RxCollectionViewSectionedReloadDataSource
    <SectionModel<String, String>>(
    configureCell: { (dataSource, collectionView, indexPath, element) in
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",
                                        for: indexPath) as! MyCollectionViewCell
        cell.label.text = "\\(element)"
        return cell}
)
 
// 绑定单元格数据
items
    .bind(to: collectionView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag)
    • 方式二:使用自定义的 Section:
// 定义布局方式以及单元格大小
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.collectionView.register(MyCollectionViewCell.self,
                             forCellWithReuseIdentifier: "Cell")
self.view.addSubview(self.collectionView!)
 
// 初始化数据
let sections = Observable.just([
    MySection(header: "", items: [
        "Swift",
        "PHP",
        "Python",
        "Java",
        "javascript",
        "C#"
        ])
    ])
 
// 创建数据源
let dataSource = RxCollectionViewSectionedReloadDataSource<MySection>(
    configureCell: { (dataSource, collectionView, indexPath, element) in
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",
                                        for: indexPath) as! MyCollectionViewCell
        cell.label.text = "\\(element)"
        return cell}
)
 
// 绑定单元格数据
sections
    .bind(to: collectionView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag)


// 自定义Section
struct MySection {
    var header: String
    var items: [Item]
}
 
extension MySection : AnimatableSectionModelType {
    typealias Item = String
     
    var identity: String {
        return header
    }
     
    init(original: MySection, items: [Item]) {
        self = original
        self.items = items
    }
}
  • 注意:RxDataSources 是以 section 来做为数据结构的,因此不管 collectionView 是单分区还是多分区,在使用 RxDataSources 的过程中,都需要返回一个 section 的数组。

② 多分区的 CollectionView

  • 如下所示,要实现如下效果:

  • 使用自带的 Section:
// 定义布局方式以及单元格大小
let flowLayout = UICollectionViewFlowLayout()
flowLayout.itemSize = CGSize(width: (SCREEN_WIDTH-50)/3.0, height: 70)
flowLayout.headerReferenceSize = CGSize(width: self.view.frame.width, height: 40)
 
// 创建集合视图
self.collectionView = UICollectionView(frame: self.view.frame,
                                       collectionViewLayout: flowLayout)
self.collectionView.backgroundColor = UIColor.white
 
// 创建一个重用的单元格
self.collectionView.register(MyCollectionViewCell.self,
                             forCellWithReuseIdentifier: "Cell")
// 创建一个重用的分区头
self.collectionView.register(MySectionHeader.self,
                             forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
                             withReuseIdentifier: "Section")
self.view.addSubview(self.collectionView!)
 

// 初始化数据
let items = Observable.just([
    SectionModel(model: "脚本语言", items: [
        "Python",
        "javascript",
        "PHP",
        ]),
    SectionModel(model: "高级语言", items: [
        "Swift",
        "C++",
        "Java",
        "C#"
        ])
    ])
 
// 创建数据源
let dataSource = RxCollectionViewSectionedReloadDataSource
    <SectionModel<String, String>>(
    configureCell: { (dataSource, collectionView, indexPath, element) in
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",
                                        for: indexPath) as! MyCollectionViewCell
        cell.label.text = "\\(element)"
        return cell},
    configureSupplementaryView: {
        (ds ,cv, kind, ip) in
        let section = cv.dequeueReusableSupplementaryView(ofKind: kind,
                    withReuseIdentifier: "Section", for: ip) as! MySectionHeader
        section.label.text = "\\(ds[ip.section].model)"
        return section
})
 
// 绑定单元格数据
items
    .bind(t

以上是关于RxSwift之UI控件UICollectionView扩展的使用的主要内容,如果未能解决你的问题,请参考以下文章

RxSwift之UI控件UICollectionView扩展的使用

RxSwift之UI控件UIButton与UIBarButtonItem扩展的使用

RxSwift之UI控件Label扩展的使用

RxSwift之UI控件UITextField与UITextView扩展的使用

RxSwift之UI控件UISwitch与UISegmentedControl扩展的使用

RxSwift之UI控件UIGestureRecognizer扩展的使用