swift中的UICollectionView粘性标题

Posted

技术标签:

【中文标题】swift中的UICollectionView粘性标题【英文标题】:UICollectionView sticky header in swift 【发布时间】:2014-12-05 12:48:59 【问题描述】:

我正在尝试创建一个粘性补充标题,它始终保持在顶部并且不会响应滚动事件。到目前为止,我发现的解决方案仍然对弹跳滚动做出反应,并使用自定义 flowLayout 进行修复,这也可能是我的问题的修复。

我想要这样的原因是标题在其他地方使用并且应该是可重用的。我希望这可以通过这种方式解决,并且我不必创建单独的视图。

因为我在 Swift 中做这件事,所以在 Swift 中有一个例子会很棒。

【问题讨论】:

【参考方案1】:

ios 9 + 最简单的解决方案,因为它不需要编写 UICollectionViewFlowLayout 的子类。

在带有 collectionView 的 viewController 的 viewDidLoad 中使用以下代码:

let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout // casting is required because UICollectionViewLayout doesn't offer header pin. Its feature of UICollectionViewFlowLayout
layout?.sectionHeadersPinToVisibleBounds = true

@Antoine 也暗示了这一点。

【讨论】:

这个方法有效,但是我想知道为什么sectionheader遇到footer时会被推上去 这太棒了!最佳解决方案。 绝对是最直接且易于使用的解决方案。 现在可以放弃 iOS 8,这个答案太棒了:D 这太棒了!【参考方案2】:

我找到的最终解决方案:

使用这个自定义流布局可以修复这个粘性标题:

class StickyHeaderCollectionViewFlowLayout: UICollectionViewFlowLayout 

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? 

        var superAttributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect) as? [UICollectionViewLayoutAttributes]

        if superAttributes == nil 
            // If superAttributes couldn't cast, return
            return super.layoutAttributesForElementsInRect(rect)
        

        let contentOffset = collectionView!.contentOffset
        var missingSections = NSMutableIndexSet()

        for layoutAttributes in superAttributes! 
            if (layoutAttributes.representedElementCategory == .Cell) 
                if let indexPath = layoutAttributes.indexPath 
                    missingSections.addIndex(layoutAttributes.indexPath.section)
                
            
        

        for layoutAttributes in superAttributes! 
            if let representedElementKind = layoutAttributes.representedElementKind 
                if representedElementKind == UICollectionElementKindSectionHeader 
                    if let indexPath = layoutAttributes.indexPath 
                        missingSections.removeIndex(indexPath.section)
                    
                
            
        

        missingSections.enumerateIndexesUsingBlock  idx, stop in
            let indexPath = NSIndexPath(forItem: 0, inSection: idx)
            if let layoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath) 
                superAttributes!.append(layoutAttributes)
            
        

        for layoutAttributes in superAttributes! 
            if let representedElementKind = layoutAttributes.representedElementKind 
                if representedElementKind == UICollectionElementKindSectionHeader 
                    let section = layoutAttributes.indexPath!.section
                    let numberOfItemsInSection = collectionView!.numberOfItemsInSection(section)

                    let firstCellIndexPath = NSIndexPath(forItem: 0, inSection: section)!
                    let lastCellIndexPath = NSIndexPath(forItem: max(0, (numberOfItemsInSection - 1)), inSection: section)!


                    let (firstCellAttributes: UICollectionViewLayoutAttributes, lastCellAttributes: UICollectionViewLayoutAttributes) = 
                        if (self.collectionView!.numberOfItemsInSection(section) > 0) 
                            return (
                                self.layoutAttributesForItemAtIndexPath(firstCellIndexPath),
                                self.layoutAttributesForItemAtIndexPath(lastCellIndexPath))
                         else 
                            return (
                                self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: firstCellIndexPath),
                                self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionFooter, atIndexPath: lastCellIndexPath))
                        
                        ()

                    let headerHeight = CGRectGetHeight(layoutAttributes.frame)
                    var origin = layoutAttributes.frame.origin

                    origin.y = min(contentOffset.y, (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight))
                    // Uncomment this line for normal behaviour:
                    // origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttributes.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight))

                    layoutAttributes.zIndex = 1024
                    layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)
                
            
        

        return superAttributes
    

    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool 
        return true
    


要创建一个标题像传统一样粘性的布局,请更改此行:

origin.y = min(contentOffset.y, (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight))

到这一行:

origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight))

希望这对其他人有用!

更新

已更新以修复崩溃(感谢 Robert Atkins!)以及 Swift 1.2 的一些更新

tvOS 和 iOS 9

tvOS 和 iOS 9 引入了可以使用的属性sectionHeadersPinToVisibleBounds

【讨论】:

我在 firstCellAttrs = ... 行上遇到 EXC_ARITHMETIC 崩溃,可能与 ***.com/questions/24616797/… 相关? 显然这对我不起作用:Xcode 6.1.1 和 iOS 8 :-( 有什么想法吗?你能重新测试一下吗?标题应该像github.com/jamztang/CSStickyHeaderFlowLayout 一样贴在顶部,对吗? 不适合我的崩溃在这里self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionFooter, atIndexPath: lastCellIndexPath)) @NickWargnier 确保您的部分中至少有一个单元格。需要在上面的代码中添加修复 > sectionHeadersPinToVisibleBounds 你救了我的命,伙计!谢谢!所有其他解决方案都非常缓慢。【参考方案3】:

使用 swift 2.0 为我工作

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? 

    var superAttributes:NSMutableArray = NSMutableArray(array: super.layoutAttributesForElementsInRect(rect)!) as NSMutableArray

    let contentOffset = collectionView!.contentOffset
    var missingSections = NSMutableIndexSet()

    for layoutAttributes in superAttributes 
        if (layoutAttributes.representedElementCategory == .Cell) 
            if let indexPath = layoutAttributes.indexPath 
                missingSections.addIndex(layoutAttributes.indexPath.section)
            
        
    

    for layoutAttributes in superAttributes
        if let representedElementKind = layoutAttributes.representedElementKind 
            if representedElementKind == UICollectionElementKindSectionHeader 
                if let indexPath = layoutAttributes.indexPath 
                    missingSections.removeIndex(indexPath.section)
                
            
        
    

    missingSections.enumerateIndexesUsingBlock  idx, stop in
        let indexPath = NSIndexPath(forItem: 0, inSection: idx)
        let layoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath)
        superAttributes.addObject(layoutAttributes!)
    

    for la in superAttributes 

        let layoutAttributes = la as! UICollectionViewLayoutAttributes;

        if let representedElementKind = layoutAttributes.representedElementKind 
            if representedElementKind == UICollectionElementKindSectionHeader 
                let section = layoutAttributes.indexPath.section
                let numberOfItemsInSection = collectionView!.numberOfItemsInSection(section)

                let firstCellIndexPath = NSIndexPath(forItem: 0, inSection: section)
                let lastCellIndexPath = NSIndexPath(forItem: max(0, (numberOfItemsInSection - 1)), inSection: section)                    

                var firstCellAttributes:UICollectionViewLayoutAttributes
                var lastCellAttributes:UICollectionViewLayoutAttributes

                    if (self.collectionView!.numberOfItemsInSection(section) > 0) 
                            firstCellAttributes = self.layoutAttributesForItemAtIndexPath(firstCellIndexPath)!
                            lastCellAttributes = self.layoutAttributesForItemAtIndexPath(lastCellIndexPath)!
                     else 
                            firstCellAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: firstCellIndexPath)!
                            lastCellAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionFooter, atIndexPath: lastCellIndexPath)!
                    

                let headerHeight = CGRectGetHeight(layoutAttributes.frame)
                var origin = layoutAttributes.frame.origin

                 origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttributes.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight))
                ;

                layoutAttributes.zIndex = 1024;
                layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)

            
        
    

    return NSArray(array: superAttributes) as? [UICollectionViewLayoutAttributes]


override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool 
    return true

【讨论】:

此代码仅适用于垂直滚动,您可以使其适用于水平滚动吗?和顶部的部分标题?【参考方案4】:

按照this gist 中的建议,我通过测试空部分来修复我的崩溃问题。我还添加了几个if lets 以获得额外的 Swift 风格点 ;-)。现在这对我有用:

class StickyHeaderCollectionViewFlowLayout: UICollectionViewFlowLayout 

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? 

        var answer: [UICollectionViewLayoutAttributes] = super.layoutAttributesForElementsInRect(rect)! as [UICollectionViewLayoutAttributes]
        let contentOffset = collectionView!.contentOffset

        var missingSections = NSMutableIndexSet()

        for layoutAttributes in answer 
            if (layoutAttributes.representedElementCategory == .Cell) 
                if let indexPath = layoutAttributes.indexPath 
                    missingSections.addIndex(layoutAttributes.indexPath.section)
                
            
        

        for layoutAttributes in answer 
            if let representedElementKind = layoutAttributes.representedElementKind 
                if representedElementKind == UICollectionElementKindSectionHeader 
                    if let indexPath = layoutAttributes.indexPath 
                        missingSections.removeIndex(indexPath.section)
                    
                
            
        

        missingSections.enumerateIndexesUsingBlock  idx, stop in
            let indexPath = NSIndexPath(forItem: 0, inSection: idx)
            if let layoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath) 
                answer.append(layoutAttributes)
            
        

        for layoutAttributes in answer 
            if let representedElementKind = layoutAttributes.representedElementKind 
                if representedElementKind == UICollectionElementKindSectionHeader 
                    let section = layoutAttributes.indexPath!.section
                    let numberOfItemsInSection = collectionView!.numberOfItemsInSection(section)

                    let firstCellIndexPath = NSIndexPath(forItem: 0, inSection: section)!
                    let lastCellIndexPath = NSIndexPath(forItem: max(0, (numberOfItemsInSection - 1)), inSection: section)!


                    let (firstCellAttributes: UICollectionViewLayoutAttributes, lastCellAttributes: UICollectionViewLayoutAttributes) = 
                        if (self.collectionView!.numberOfItemsInSection(section) > 0) 
                            return (
                                self.layoutAttributesForItemAtIndexPath(firstCellIndexPath),
                                self.layoutAttributesForItemAtIndexPath(lastCellIndexPath))
                         else 
                            return (
                                self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: firstCellIndexPath),
                                self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionFooter, atIndexPath: lastCellIndexPath))
                        
                    ()

                    let headerHeight = CGRectGetHeight(layoutAttributes.frame)
                    var origin = layoutAttributes.frame.origin

                    origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttributes.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight))

                    layoutAttributes.zIndex = 1024
                    layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)
                
            
        

        return answer
    

    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool 
        return true
    


【讨论】:

谢谢!我已经用你更新的部分代码更新了我的答案。 谢谢!仅供参考,在 Swift 1.2 中,layoutAttributesForElementsIntRect 的第一行现在需要一个“as!” var 答案:[UICollectionViewLayoutAttributes] = super.layoutAttributesForElementsInRect(rect)!作为! [UICollectionViewLayoutAttributes] 我在 swift 2.0 中的 let (firstCellAttributes: UICollectionViewLayoutAttributes, lastCellAttributes: UICollectionViewLayoutAttributes) = 处遇到“定义与先前值冲突”【参考方案5】:

Irina 答案的 Cleaner Swift 2.3 测试版

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? 

    guard var superAttributes = super.layoutAttributesForElementsInRect(rect) else 
        return super.layoutAttributesForElementsInRect(rect)
    

    let contentOffset = collectionView!.contentOffset
    let missingSections = NSMutableIndexSet()

    for layoutAttributes in superAttributes 
        if (layoutAttributes.representedElementCategory == .Cell) 
            missingSections.addIndex(layoutAttributes.indexPath.section)
        

        if let representedElementKind = layoutAttributes.representedElementKind 
            if representedElementKind == UICollectionElementKindSectionHeader 
                missingSections.removeIndex(layoutAttributes.indexPath.section)
            
        
    

    missingSections.enumerateIndexesUsingBlock  idx, stop in
        let indexPath = NSIndexPath(forItem: 0, inSection: idx)
        if let layoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath) 
            superAttributes.append(layoutAttributes)
        
    

    for layoutAttributes in superAttributes 
        if let representedElementKind = layoutAttributes.representedElementKind 
            if representedElementKind == UICollectionElementKindSectionHeader 
                let section = layoutAttributes.indexPath.section
                let numberOfItemsInSection = collectionView!.numberOfItemsInSection(section)

                let firstCellIndexPath = NSIndexPath(forItem: 0, inSection: section)
                let lastCellIndexPath = NSIndexPath(forItem: max(0, (numberOfItemsInSection - 1)), inSection: section)

                var firstCellAttributes:UICollectionViewLayoutAttributes
                var lastCellAttributes:UICollectionViewLayoutAttributes

                if (self.collectionView!.numberOfItemsInSection(section) > 0) 
                    firstCellAttributes = self.layoutAttributesForItemAtIndexPath(firstCellIndexPath)!
                    lastCellAttributes = self.layoutAttributesForItemAtIndexPath(lastCellIndexPath)!
                 else 
                    firstCellAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: firstCellIndexPath)!
                    lastCellAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionFooter, atIndexPath: lastCellIndexPath)!
                

                let headerHeight = CGRectGetHeight(layoutAttributes.frame)
                var origin = layoutAttributes.frame.origin

                origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttributes.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight))
                ;

                layoutAttributes.zIndex = 1024;
                layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)

            
        
    

    return superAttributes

【讨论】:

【参考方案6】:

根据 GregP 的回答测试了 Swift 2.2 版本。 Greg 的代码在 lastCellIndexPath 处抛出了一个 unwrap optional 错误,因为节数最初为零。所以我移动了 numberOfItemsInSection > 0 检查。

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? 

    let superAttributes:NSMutableArray = NSMutableArray(array: super.layoutAttributesForElementsInRect(rect)!) as NSMutableArray

    let contentOffset = collectionView!.contentOffset
    let missingSections = NSMutableIndexSet()

    for layoutAttributes in superAttributes 
        if (layoutAttributes.representedElementCategory == .Cell) 
            if let _ = layoutAttributes.indexPath 
                missingSections.addIndex(layoutAttributes.indexPath.section)
            
        
    

    for layoutAttributes in superAttributes
        if let representedElementKind = layoutAttributes.representedElementKind 
            if representedElementKind == UICollectionElementKindSectionHeader 
                if let indexPath = layoutAttributes.indexPath 
                    missingSections.removeIndex(indexPath.section)
                
            
        
    

    missingSections.enumerateIndexesUsingBlock  idx, stop in
        let indexPath = NSIndexPath(forItem: 0, inSection: idx)
        let layoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath)
        superAttributes.addObject(layoutAttributes!)
    

    for la in superAttributes 

        let layoutAttributes = la as! UICollectionViewLayoutAttributes;

        if let representedElementKind = layoutAttributes.representedElementKind 
            if representedElementKind == UICollectionElementKindSectionHeader 
                let section = layoutAttributes.indexPath.section
                let numberOfItemsInSection = collectionView!.numberOfItemsInSection(section)

                if numberOfItemsInSection > 0
                    let firstCellIndexPath = NSIndexPath(forItem: 0, inSection: section)
                    let lastCellIndexPath = NSIndexPath(forItem: max(0, (numberOfItemsInSection - 1)), inSection: section)

                    var firstCellAttributes:UICollectionViewLayoutAttributes
                    var lastCellAttributes:UICollectionViewLayoutAttributes

                    firstCellAttributes = self.layoutAttributesForItemAtIndexPath(firstCellIndexPath)!
                    lastCellAttributes = self.layoutAttributesForItemAtIndexPath(lastCellIndexPath)!

                    let headerHeight = CGRectGetHeight(layoutAttributes.frame)
                    var origin = layoutAttributes.frame.origin

                    origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttributes.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight));

                    layoutAttributes.zIndex = 1024;
                    layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)
                
            
        
    

    return NSArray(array: superAttributes) as? [UICollectionViewLayoutAttributes]


override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool 
    return true

【讨论】:

【参考方案7】:

对于想要在组合布局上使用置顶标题的人:

(根据需要更改高度值)

let headerKind = UICollectionView.elementKindSectionHeader
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(100))
    
let headerElement = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: headerKind, alignment: .top)
// for sticky header
headerElement.pinToVisibleBounds = true
    
section.boundarySupplementaryItems = [headerElement]

【讨论】:

【参考方案8】:

如果您只有一个部分,这是一个简单的解决方案。

class StickyHeaderLayout: UICollectionViewFlowLayout 

  override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool 
    return true
  

  override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? 
    var attributes = super.layoutAttributesForElementsInRect(rect)! as! [UICollectionViewLayoutAttributes]

      let offset          = collectionView?.contentOffset


      for attrs in attributes 
        if attrs.representedElementKind == nil 
          let indexPath        = NSIndexPath(forItem: 0, inSection: attrs.indexPath.section)
          let layoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath)

          attributes.append(layoutAttributes)
        
      

      for attrs in attributes 
        if attrs.representedElementKind == nil 
          continue
        

        if attrs.representedElementKind == UICollectionElementKindSectionHeader 

          var headerRect = attrs.frame
          headerRect.size.height = headerHeight
          headerRect.origin.y = offset!.y
          attrs.frame = headerRect
          attrs.zIndex = 1024
          break
        
      

    return attributes
  

【讨论】:

【参考方案9】:

Swift 3 版本试图避免 ! 的意义所在。

class StickyHeaderCollectionViewFlowLayout: UICollectionViewFlowLayout 

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? 
        guard var superAttributes = super.layoutAttributesForElements(in: rect), let collectionView = collectionView else 
            return super.layoutAttributesForElements(in: rect)
        

        let collectionViewTopY = collectionView.contentOffset.y + collectionView.contentInset.top
        let contentOffset = CGPoint(x: 0, y: collectionViewTopY)
        let missingSections = NSMutableIndexSet()

        superAttributes.forEach  layoutAttributes in
            if layoutAttributes.representedElementCategory == .cell && layoutAttributes.representedElementKind != UICollectionElementKindSectionHeader 
                missingSections.add(layoutAttributes.indexPath.section)
            
        

        missingSections.enumerate(using:  idx, stop in
            let indexPath = IndexPath(item: 0, section: idx)
            if let layoutAttributes = self.layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionHeader, at: indexPath) 
                superAttributes.append(layoutAttributes)
            
        )

        for layoutAttributes in superAttributes 
            if let representedElementKind = layoutAttributes.representedElementKind 
                if representedElementKind == UICollectionElementKindSectionHeader 
                    let section = layoutAttributes.indexPath.section
                    let numberOfItemsInSection = collectionView.numberOfItems(inSection: section)

                    let firstCellIndexPath = IndexPath(item: 0, section: section)
                    let lastCellIndexPath = IndexPath(item: max(0, (numberOfItemsInSection - 1)), section: section)                   

                    let cellAttributes:(first: UICollectionViewLayoutAttributes, last: UICollectionViewLayoutAttributes) = 
                        if (collectionView.numberOfItems(inSection: section) > 0) 
                            return (
                                self.layoutAttributesForItem(at: firstCellIndexPath)!,
                                self.layoutAttributesForItem(at: lastCellIndexPath)!)
                         else 
                            return (
                                self.layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionHeader, at: firstCellIndexPath)!,
                                self.layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionFooter, at: lastCellIndexPath)!)
                        
                    ()

                    let headerHeight = layoutAttributes.frame.height
                    var origin = layoutAttributes.frame.origin
                    // This line makes only one header visible fixed at the top
//                    origin.y = min(contentOffset.y, cellAttributes.last.frame.maxY - headerHeight)
                    // Uncomment this line for normal behaviour:
                    origin.y = min(max(contentOffset.y, cellAttributes.first.frame.minY - headerHeight), cellAttributes.last.frame.maxY - headerHeight)

                    layoutAttributes.zIndex = 1024
                    layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)
                
            
        

        return superAttributes
    

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool 
        return true
    

【讨论】:

【参考方案10】:

我在我的项目中使用它。希望对您有所帮助。

    func collectionView(collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    referenceSizeForHeaderInSection section: Int) -> CGSize

    return CGSizeMake(UIScreen.mainScreen().bounds.width, 40)

当然。你可以返回任何你想要的尺寸。

【讨论】:

以上是关于swift中的UICollectionView粘性标题的主要内容,如果未能解决你的问题,请参考以下文章

带有粘性水平指示器的 UICollectionView Swift 3.0

具有特定于部分的布局和粘性标题的 UICollectionView

如何在顶部 UICollectionView 上制作粘性标题

UICollectionView 的标题视图在滚动时不断重复 - 如何创建固定(非粘性)的单个集合视图标题?

淡出 UICollectionView 中的项目

Swift 3 中的 UICollectionView + NSFetchedResultsController