具有多个部分的 UICollectionView

UICollectionView with multiple sections

大家好,我需要在水平滚动的 collectionView 中显示 2 个部分。

在第一部分我需要 10 个单元格,在第二部分我需要 9 个单元格

我已经用这种方式实现了,但我不明白为什么当我 select 第 2 节的单元格时 indexPath.item 的值是第 1 节 [=14= 的单元格的值]

编辑

如您所见,我的 collectionView 有 2 个部分,设置单元格是这样的。我不需要像这样显示单元格,但我需要第 1 部分位于第一行并且它必须显示这样的项目都在同一行 (0,1 2 3 4 5) 和底部行的第 2 部分,并显示与顶部行相同的项目

我哪里做错了?

private func commonInit() -> Void {
        backgroundColor = .clear
        
        let cv = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
        cv.backgroundColor = .clear
        cv.delegate = self
        cv.dataSource = self
        cv.isPagingEnabled = true
        cv.showsHorizontalScrollIndicator = false
        addSubview(cv)
            
        if let layout = cv.collectionViewLayout as? UICollectionViewFlowLayout {
            layout.scrollDirection = .horizontal }
        
        TimeSelectorCell.register(in: cv)
        
        cv.anchor(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)

    }

    func numberOfSections(in collectionView: UICollectionView) -> Int { 2 }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if section == 0 { return 10 }
        else { return 9 }
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimeSelectorCell.cellIdentifier, for: indexPath) as! TimeSelectorCell
    
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print(indexPath.item)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        .init(width: collectionView.frame.width / 4 , height: collectionView.frame.height / 2)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 0 }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 0 }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 
     
    if (indexPath.section == 0 )
    {
      // cell of section 1
       print(indexPath.item)
    }else{
     // cell of section 2
      print(indexPath.item)
     }
     
   
}

你可以试试!

在这种情况下,您必须使用 iOS 13 的 CollectionView Compositional Layouts。这里有2个教程让你了解它 -

  1. https://www.zealousweb.com/how-to-use-compositional-layout-in-collection-view/
  2. https://medium.com/better-programming/ios-13-compositional-layouts-in-collectionview-90a574b410b8
  3. WWDC 视频 - https://developer.apple.com/videos/play/wwdc2019/215/

对于您的情况,我已经调整了第二个教程中的示例

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return (section == 0) ? 10 : 9
}


func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 2
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    print(indexPath)
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimeSelectorCell.cellIdentifier, for: indexPath) as! TimeSelectorCell
    
    return cell
}

private func commonInit() {
    let cv = UICollectionView(frame: view.bounds, collectionViewLayout: createLayoutDiffSection())
    cv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    TimeSelectorCell.register(in: cv)
    
    cv.dataSource = self
    cv.delegate = self
    
    addSubview(cv)
}

到目前为止,它与您的代码几乎相同。现在 createLayoutDiffSection() 方法是 -

func createLayoutDiffSection() -> UICollectionViewLayout {
    
    let layout = UICollectionViewCompositionalLayout { (sectionIndex: Int,
        layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
        
        let seperateFlow = true
        
        let columns = (sectionIndex == 0) ? 10 : 9
        
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                              heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 2, bottom: 0, trailing: 2)
        
        let groupHeight = NSCollectionLayoutDimension.fractionalWidth(0.2)

let widthFraction:CGFloat = (sectionIndex == 0) ? 1 : 0.9
        
        let groupSizeWidth:CGFloat = seperateFlow ? (widthFraction * 2) : 1
        
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(groupSizeWidth),
                                               heightDimension: groupHeight)
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: columns)
        
        let section = NSCollectionLayoutSection(group: group)
        if seperateFlow {
            section.orthogonalScrollingBehavior = .continuous
        }
        section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 0, bottom: 20, trailing: 0)
        return section
    }
    return layout
}

如果两个部分的滚动不是分开的,则设置 -

let seperateFlow = false

这里要理解的要点是 -

尺码类

我们可以根据需要使用四种大小选项,这样就无需计算即可获得所需的输出。让我们看看所有的尺寸 类:

  1. fractionalWidth():使用 fractionalWidth 我们可以设置 width/height 单元格的比例与其 parent 的宽度
  2. 小数高度(): 使用 fractionalHeight,我们可以设置单元格的 width/height 与其 parent 的高度成比例
  3. absolute(): 使用绝对 值,我们可以将单元格的width/height设置为固定值
  4. estimate():使用估计值,我们可以设置单元格的width/height 根据内容大小。系统会决定最优 width/height 内容。

核心概念

要构建任何组合布局,需要实现以下四个 类:

  1. NSCollectionLayoutSize — 宽度和高度尺寸是 输入 NSCollectionLayoutDimension 可以通过设置 布局的小数 width/height(相对于它的百分比 容器),或通过设置绝对或估计大小。
  2. NSCollectionLayoutItem — 这是布局的单元格 基于尺寸的屏幕。
  3. NSCollectionLayoutGroup — 它以水平、垂直或自定义形式保存 NSCollectionLayoutItem。
  4. NSCollectionLayoutSection — 这用于通过传递 NSCollectionLayoutGroup 来初始化该部分。部分最终构成组合布局。