【问题标题】:Swift: How to Optionally return a header for a collection view section?Swift:如何选择返回集合视图部分的标题?
【发布时间】:2021-01-09 00:57:52
【问题描述】:

我有一个UICollectionViewDiffableDataSource,就像这样:

var data:UICollectionViewDiffableDataSource<Section, Message>!

我这样定义我的部分标题的布局:

let header = NSCollectionLayoutBoundarySupplementaryItem(
    layoutSize: .init(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(10)),
    elementKind: UICollectionView.elementKindSectionHeader,
    alignment: .top
)
section.boundarySupplementaryItems = [header]

最后,要返回我的标题,我有这个函数可以返回 UICollectionReusableView,如下所示:

func setupHeaderData() {
    data.supplementaryViewProvider = { collectionView, kind, indexPath in
        return DateStampBuilder(data: self.data, style: self.style).build(collectionView: collectionView, kind: kind, indexPath: indexPath)
    }
}

太棒了:我可以在UICollectionView 中看到我的标题。

我想要什么:我怎样才能有选择地决定不显示特定部分的特定标题?

当我尝试在以下函数中返回 nil 时:

data.supplementaryViewProvider = { collectionView, kind, indexPath in

我收到以下错误:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath (UICollectionElementKindSectionHeader,<NSIndexPath: 0xb461f3e1dd0c21dc> {length = 2, path = 0 - 0}) was not retrieved by calling -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: or is nil ((null))'

我对如何“可选地”返回一个部分的标题的唯一想法是注册另一个高度为零的标题视图,并在我根本不想返回任何标题时返回此标题。

但对我来说,这似乎有点混乱,如果我在不显示标题时可以返回 nil 会更干净。

我做错了什么?


感谢您的帮助!

【问题讨论】:

    标签: ios swift uicollectionview uicollectionviewcompositionallayout uicollectionviewdiffabledatasource


    【解决方案1】:

    这应该在为 collectionView 创建布局时完成。这是一个关于如何使用UICollectionLayoutListConfiguration 的示例:

    let sectionProvider = { [weak self] (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
            var section: NSCollectionLayoutSection
            
            var listConfiguration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
            
            if condition {
                listConfiguration.headerMode = .supplementary
            } else {
                listConfiguration.headerMode = .none
            }
            
            section = NSCollectionLayoutSection.list(using: listConfiguration, layoutEnvironment: layoutEnvironment)
            return section
        }
        
    let layout = UICollectionViewCompositionalLayout(sectionProvider: sectionProvider)
        
    collectionView.setCollectionViewLayout(layout, animated: true)
    

    您的条件显然可以绑定到您的数据源和部分索引,因此您不会与动态创建的部分不同步。

    【讨论】:

      【解决方案2】:

      我最近正在研究这个问题,我想出的解决方案是根据在 supplementaryViewProvider 闭包上返回 nil 所使用的相同条件,选择性地设置组合布局 boundarySupplementaryItems

      一些伪代码:

      给定条件

      let myCondition = ...
      

      我的补充视图提供者:

      dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in 
          // ...
          guard myCondition else { return nil }
      }
      

      在您的组合布局提供程序函数/闭包中,您可以:

      let section = NSCollectionLayoutSection(...)
      if myCondition {
          let header = NSCollectionLayoutBoundarySupplementaryItem(...)
          section.boundarySupplementaryItems = [header]
      }
      

      这将允许您从 supplementaryViewProvider 闭包返回 nil,因为当条件为 true 时,集合视图永远不会请求补充视图(如果这样做,您仍然会看到崩溃)。

      【讨论】:

        【解决方案3】:

        有点丑陋的解决方案,但我创建了一个简单的空视图:

        class EmptyHeader : UICollectionReusableView {    
            static var reuseIdentifier:String = "spacer"
        }
        

        然后,当我不想要标题时,我只返回此视图。 (确保先将视图注册到collectionview)。

        【讨论】:

          猜你喜欢
          • 2019-05-10
          • 2017-08-18
          • 1970-01-01
          • 2018-12-26
          • 2015-05-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-01
          • 1970-01-01
          相关资源
          最近更新 更多