【问题标题】:Self sizing collectionViewCells using RxDataSource使用 RxDataSource 自行调整 collectionViewCells 的大小
【发布时间】:2021-09-27 08:13:56
【问题描述】:

如何使用 RxDataSource 实现 self-sizing 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里面?

【问题讨论】:

    标签: rx-swift rxdatasources


    【解决方案1】:

    将集合视图添加到情节提要。将 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
        }
      }
    

    Collection View Cell 类

    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)
              ])
      }
    }
    

    【讨论】:

      【解决方案2】:

      遇到类似问题,这样解决

      // 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
      

      【讨论】:

        猜你喜欢
        • 2020-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-12
        • 1970-01-01
        • 1970-01-01
        • 2012-06-09
        • 2010-11-01
        相关资源
        最近更新 更多