RxSwift 和 UICollectionView 标头

ale*_*xjk 7 ios uicollectionview swift rx-swift

我正在使用RxSwift我的UIViewController包含UICollectionView. 我试图在我的集合视图中添加一个标题,但从未调用过:

func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath)
Run Code Online (Sandbox Code Playgroud)

ser*_*ych 6

我有同样的问题。解决它移动到RxCollectionViewSectionedReloadDataSource

这种类型的数据源有页眉/页脚。标准RxCollectionViewReactiveArrayDataSource没有页眉/页脚。

即使在 RxCocoa UICollectionView+Rx扩展中也给出了 RxCollectionViewSectionedReloadDataSource 作为示例。

直接来自 UICollectionView+Rx 的示例:

     let dataSource = RxCollectionViewSectionedReloadDataSource<SectionModel<String, Double>>()

     let items = Observable.just([
         SectionModel(model: "First section", items: [
             1.0,
             2.0,
             3.0
         ]),
         SectionModel(model: "Second section", items: [
             1.0,
             2.0,
             3.0
         ]),
         SectionModel(model: "Third section", items: [
             1.0,
             2.0,
             3.0
         ])
     ])

     dataSource.configureCell = { (dataSource, cv, indexPath, element) in
         let cell = cv.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! NumberCell
         cell.value?.text = "\(element) @ row \(indexPath.row)"
         return cell
     }

     items
        .bind(to: collectionView.rx.items(dataSource: dataSource))
        .disposed(by: disposeBag)
Run Code Online (Sandbox Code Playgroud)


Bro*_*ois 6

经过很长时间的弄清楚,我有了一个完整的答案。关键部分取决于 RxDataSources dataSource.configureCelldataSource.supplementaryViewFactory。

您需要通过正常注册笔尖进行设置。要使集合视图显示其标题,您需要定义标题大小。使用集合流布局允许您保留可能在单击处理程序的单元格内具有的任何绑定,并且不会覆盖 RxCocoa 在内部使用的 rx 委托代理。

在这个例子中,我有一个用于整个屏幕的 viewModel ,它包含一个 RxVariable ,其中包含集合视图中每个项目的 itemViewModels 数组。

带有使用 RxSwift、RxDataSources 和 RxCocoa 的标头的 UICollectionView:

var disposeBag: DisposeBag? = DisposeBag()

@IBOutlet weak var collectionView: UICollectionView!

let dataSource = RxCollectionViewSectionedReloadDataSource<SectionModel<String, ItemViewModel>>()
 
override func viewDidLoad() {
    super.viewDidLoad()
    registerHeaderCell()
    registerCollectionViewCell()
    setupLayout()
    bindViewModelToCollectionView()
}

private func registerHeaderCell() {
    let nib = UINib(nibName: "HeaderCell", bundle: nil)
    collectionView.register(nib, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderReuseId")
}

private func registerCollectionViewCell() {
    let nib = UINib(nibName:"CollectionViewCell", bundle: nil)
    collectionView.register(nib, forCellWithReuseIdentifier: "CellReuseId")
}

private func setupLayout(){
    let layout = UICollectionViewFlowLayout()
    layout.headerReferenceSize = CGSize(width: UIScreen.main.bounds.width, height: 100)
    collectionView.setCollectionViewLayout(layout, animated: false)
}

private func bindViewModelToCollectionView(){
    dataSource.supplementaryViewFactory = {(dataSource, collectionView, kind, indexPath) -> UICollectionReusableView in
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderReuseId", for: indexPath) as! HeaderCell
        header.setup()
        return header
    }
    
    dataSource.configureCell = {(datasource, collectionView, indexPath, itemViewModel) -> UICollectionViewCell in
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellReuseId", for: indexPath) as! CollectionViewCell
        cell.setup()
        return cell
    } 

    viewModel.itemViewModels.asObservable().map { 
        (itemViewModels) -> [SectionModel<String, ItemViewModel>] in
       //my particular app has one big section but you can use this for mutiple sections like Sergiy's answer   
         return [SectionModel(model: "", items: itemViewModels)]
    }.bind(to: collectionView.rx.items(dataSource: dataSource))
    .addDisposableTo(disposeBag!)
}

deinit {
    disposeBag = nil
}
Run Code Online (Sandbox Code Playgroud)


sol*_*ell -3

它与 无关RxSwift,除非您正在使用RxDataSources,也就是说。

您只是没有正确设置UICollectionView。除其他事项外:

  • 确保您定义func numberOfSections(in collectionView: UICollectionView) -> Int返回大于 的值0
  • 确保您定义func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize返回的大小大于CGSize(width: 0, height: 0)
  • 如果您使用的是nib,则将其注册到func register(_ nib: UINib?, forSupplementaryViewOfKind kind: String, withReuseIdentifier identifier: String)。或者,如果您以编程方式创建它,则将其注册到func register(_ viewClass: AnyClass?, forSupplementaryViewOfKind elementKind: String, withReuseIdentifier identifier: String).