3

如何使用 RxDataSource 实现自定大小 collectionViewCells?

我试过设置

flowLayout.estimatedItemSize = CGSize(width: 187, height: 102)

但是当dataSourceObservable更改时应用程序崩溃。

我试过在里面设置单元格大小

dataSource.configureCell = { [weak self] (dataSource, collectionView, indexPath, _) in 

这不是一个好主意,因为单元格重叠,这是因为我没有使用

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

现在,是否可以仅使用 observables 正确布局单元格大小?那不是叫类似的东西

dataSourceVar.value[indexPath].cellSize

里面collectionView sizeForItemAt

4

2 回答 2

0

遇到类似问题,这样解决

// swiftlint:disable line_length type_name
final class RxCollectionViewSectionedReloadDataSourceAndDelegate<Section: SectionModelType>: RxCollectionViewSectionedReloadDataSource<Section>, UICollectionViewDelegateFlowLayout {
    typealias CellSize = (CollectionViewSectionedDataSource<Section>, UICollectionView, UICollectionViewLayout, IndexPath, Item) -> CGSize
    typealias SizeViewInSection = (CollectionViewSectionedDataSource<Section>, UICollectionView, UICollectionViewLayout, Int, Section) -> CGSize
    
    private var cellSize: CellSize
    private var headerSectionViewSize: SizeViewInSection?
    private var footerSectionViewSize: SizeViewInSection?
    
    init(
        configureCell: @escaping ConfigureCell,
        configureSupplementaryView: ConfigureSupplementaryView? = nil,
        moveItem: @escaping MoveItem = { _, _, _ in () },
        canMoveItemAtIndexPath: @escaping CanMoveItemAtIndexPath = { _, _ in false },
        cellSize: @escaping CellSize,
        headerSectionViewSize: SizeViewInSection? = nil,
        footerSectionViewSize: SizeViewInSection? = nil
    ) {
        self.cellSize = cellSize
        self.headerSectionViewSize = headerSectionViewSize
        self.footerSectionViewSize = footerSectionViewSize
        super.init(
            configureCell: configureCell,
            configureSupplementaryView: configureSupplementaryView,
            moveItem: moveItem,
            canMoveItemAtIndexPath: canMoveItemAtIndexPath
        )
    }
    
    override func collectionView(
        _ collectionView: UICollectionView,
        observedEvent: Event<RxCollectionViewSectionedReloadDataSource<Section>.Element>
    ) {
        collectionView.delegate = self
        super.collectionView(collectionView, observedEvent: observedEvent)
    }
    
    func collectionView(
        _ collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        sizeForItemAt indexPath: IndexPath
    ) -> CGSize {
        cellSize(self, collectionView, collectionViewLayout, indexPath, self[indexPath])
    }
    
    func collectionView(
        _ collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        referenceSizeForHeaderInSection section: Int
    ) -> CGSize {
        headerSectionViewSize?(self, collectionView, collectionViewLayout, section, sectionModels[section]) ?? .zero
    }
    
    func collectionView(
        _ collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        referenceSizeForFooterInSection section: Int
    ) -> CGSize {
        footerSectionViewSize?(self, collectionView, collectionViewLayout, section, sectionModels[section]) ?? .zero
    }
}
// swiftlint:enable line_length type_name
于 2021-09-24T18:34:10.607 回答
0

将集合视图添加到情节提要。将 RxDataSources 作为依赖项导入。

import UIKit
import RxSwift
import RxCocoa
import RxDataSources

class ViewController: UIViewController {

  private let disposeBag = DisposeBag()
  
  @IBOutlet weak var collectionView: UICollectionView!
  @IBOutlet weak var collectionLayout: UICollectionViewFlowLayout! {
    didSet {
      collectionLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    }
  }
  
  private let section = BehaviorRelay(
    value: Section(items: [
      Item(title: "Lorem ipsum dolor sit amet, consectetur"),
      Item(title: "adipiscing elit, sed do eiusmod tempor"),
      Item(title: "incididunt ut labore et dolore magna aliqua"),
      Item(title: "Ut enim ad minim veniam"),
      Item(title: "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."),
      Item(title: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
      ]
    )
  )

  private lazy var collectionDatasource = {
    return RxCollectionViewSectionedReloadDataSource<Section>(
      configureCell: { (dataSource, collectionView, indexPath, item) -> UICollectionViewCell in
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionCell
        cell.titleLabel.text = item.title
        cell.layer.borderWidth = 0.5
        cell.layer.borderColor = UIColor.lightGray.cgColor
        cell.maxWidth = collectionView.bounds.width - 16
        return cell
    })
  }()
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    initCollection()
  }
  
  private func initCollection() {
    section
      .asObservable()
      .map({ return [$0] })
      .bind(to: collectionView.rx.items(dataSource: collectionDatasource))
      .disposed(by: disposeBag)
  }
}

数据模型

  import Foundation
  
  struct Item {
    let title: String
  }

创建Section类继承SectionModelType

import RxDataSources

  struct Section {
    var items: [Item]
  }
  
  extension Section: SectionModelType {
    
    init(
      original: Section,
      items: [Item]) {
      
      self = original
      self.items = items
    }
  }

集合视图单元格类

import UIKit

class CollectionCell: UICollectionViewCell {
  @IBOutlet weak var titleLabel: UILabel!
  
  // Note: must be strong
  @IBOutlet private var maxWidthConstraint: NSLayoutConstraint! {
      didSet {
          maxWidthConstraint.isActive = false
      }
  }
  
  var maxWidth: CGFloat? = nil {
      didSet {
          guard let maxWidth = maxWidth else {
              return
          }
          maxWidthConstraint.isActive = true
          maxWidthConstraint.constant = maxWidth
      }
  }
  
  override func awakeFromNib() {
      super.awakeFromNib()
      
      contentView.translatesAutoresizingMaskIntoConstraints = false
      
      NSLayoutConstraint.activate([
          contentView.leftAnchor.constraint(equalTo: leftAnchor),
          contentView.rightAnchor.constraint(equalTo: rightAnchor),
          contentView.topAnchor.constraint(equalTo: topAnchor),
          contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
          ])
  }
}
于 2019-07-03T06:56:56.487 回答