【问题标题】:How hide header on iOS 13 Collection View Compositional Layout如何在 iOS 13 集合视图组合布局上隐藏标题
【发布时间】:2020-03-02 14:36:31
【问题描述】:

我在部署 iOS 13 组合布局时遇到了一个奇点。

我想隐藏集合视图标题并实现referenceSizeForHeaderInSection 方法,但是referenceSizeForHeaderInSection 不能在组合布局上工作

这是我的构图布局:

lazy var collectionViewLayout: UICollectionViewLayout = {
    // item layout deploy
    let cellItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(0.2))
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.33), heightDimension: .fractionalHeight(1.0))
    let cellItem = NSCollectionLayoutItem(layoutSize: cellItemSize)
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    cellItem.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)
    item.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)

    // group layout deploy
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),  heightDimension: .fractionalHeight(0.2))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)
    let containerGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),  heightDimension: .absolute(215))
    let containerGroup = NSCollectionLayoutGroup.vertical(layoutSize: containerGroupSize, subitems: [cellItem, group, group, group, group])

    // section layout deploy
    let section = NSCollectionLayoutSection(group: containerGroup)
    section.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 0, bottom: 4, trailing: 0)

    // Headers layout deploy
    let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(18))
    let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: SupplementaryViewOfKind.Header.rawValue, alignment: .top)
    section.boundarySupplementaryItems = [header]

    let layout = UICollectionViewCompositionalLayout(section: section)

    return layout
}()

实现viewForSupplementaryElementOfKind

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    guard
        kind == SupplementaryViewOfKind.Header.rawValue,
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: XXXHeader.identifier, for: indexPath) as? XXXHeader
        else { return UICollectionReusableView() }
    if isFullScreen {
        // customer header with titleLabel property
        header.titleLabel.text = segmentedControl.titleForSegment(at: indexPath.section)
    } else {
        header.titleLabel.text = nil
    }
}

然后我尝试进入referenceSizeForHeaderInSection,但无法工作

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    if isFullScreen {
        return CGSize(width: collectionView.frame.width, height: 18)
    } else {
        return CGSize.zero
    }
}

有什么想法或新方法可以隐藏合成布局标题。

【问题讨论】:

    标签: ios swift uicollectionview ios13 uicollectionviewlayout


    【解决方案1】:
    func configureDiffableDataSource() {
        let dataSource = UICollectionViewDiffableDataSource<TripSection, TripItem>(collectionView: collectionView) {
            (collectionView: UICollectionView, indexPath: IndexPath, item: TripItem) -> UICollectionViewCell? in
          let cell = collectionView.dequeueCell(ofType: SmallTableViewCell.self, for: indexPath)
          cell.fillWithData(tip)
           return cell
            }
        }
    

    //添加 elementKindSectionHeader if isFullScreen return nil

        dataSource.supplementaryViewProvider = { [weak self] (collectionView: UICollectionView, kind: String, indexPath: IndexPath) -> UICollectionReusableView? iln
            guard let itamSequence = self?.dataSource?.itemIdentifier(for: indexPath) else { return nil }
            guard let section = self?.dataSource?.snapshot().sectionIdentifier(containingItem: itamSequence) else { return nil }
           let boardHeader = collectionView.dequeueReusableView(ofType: BoardSupplementaryView.self, forKind: UICollectionView.elementKindSectionHeader, for: indexPath)
             return boardHeader
            }
        }
    
         self.dataSource = dataSource
         updateSnapshot(animated: false)
    }
    

    【讨论】:

    • 如何强制重建数据源?
    【解决方案2】:

    我做什么:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        if needHideHeaderView {
            if let headerView = collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: section)) {
                headerView.isHidden = true
            }
            return CGSize.zero
        } else {
           // other code
        }
    

    【讨论】:

    • 组合布局时不调用UICollectionViewDelegateFlowLayout,不再需要遵守UICollectionViewDelegateFlowLayout协议
    【解决方案3】:

    在生成布局时,可以传入索引

    func generateLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout {(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
            // do your layout stuff here. With sectionIndex, you can layout differently for each section
        }
        return layout
    }
    

    【讨论】:

      【解决方案4】:

      目前,除了创建自己的协议来确定是否应在部分中显示标题之外,似乎没有其他方法可以做到这一点。幸运的是,UICollectionViewCompositionalLayout 构造函数为我们提供了节索引,因此很容易做到。不要为没有它们的部分创建任何补充视图。

      protocol CollectionViewLayoutProviderDelegate: class {
          func layoutProvider(_ provider: CollectionViewLayoutProvider, shouldDisplaySupplementaryViewIn section: Int) -> Bool
      }
      
      class CollectionViewLayoutProvider {
          weak var delegate: CollectionViewLayoutProviderDelegate?
          init(delegate: CollectionViewLayoutProviderDelegate?) {
              self.delegate = delegate
          }
          
          private func prepareSupplementaryViews(section: Int) -> [NSCollectionLayoutBoundarySupplementaryItem] {
              if let delegate = delegate,
                 !delegate.layoutProvider(self, shouldDisplaySupplementaryViewIn: section) {
      // Return empty array to avoid displaying headers
      
                  return []
              }
              // Configure header if you need to
          }
          
          private func prepareSection(section: Int, group: NSCollectionLayoutGroup) -> NSCollectionLayoutSection {
              let layoutSection = NSCollectionLayoutSection(group: group)
              layoutSection.boundarySupplementaryItems = prepareSupplementaryViews(section: section)
              
              return layoutSection
          }
      }
      

      然后,在您的视图控制器中

      private lazy var layoutProvider = CollectionViewLayoutProvider(delegate: self)
      
      extension YouViewController: CollectionViewLayoutProviderDelegate {
          func layoutProvider(_ provider: CollectionViewLayoutProvider, shouldDisplaySupplementaryViewIn section: Int) -> Bool {
              return viewModel.shouldDisplayHeader(for: section) != nil
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-11-13
        • 2015-03-10
        • 1970-01-01
        • 2017-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多