如何使用 swift 在集合视图中制作页眉和页脚

How to make both header and footer in collection view with swift

如何在 swift 的集合视图中制作页眉和页脚?

我正在尝试将页眉和页脚组合在一起,但它总是崩溃,我找不到 swift 教程来理解它。

我不知道如何 return 两者的补充视图,而只是一个。

我在故事板上设置了它们(class + 标识符)

 override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
    //#warning Incomplete method implementation -- Return the number of sections
    return 2
}


override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    //#warning Incomplete method implementation -- Return the number of items in the section
    return 10
}




override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
    var header: headerCell!
    var footer: footerCell!



    if kind == UICollectionElementKindSectionHeader {
        header =
            collectionView.dequeueReusableSupplementaryViewOfKind(kind,
                withReuseIdentifier: "header", forIndexPath: indexPath)
            as? headerCell

}
    return header

}

Error: UICollectionElementKindCell with identifier one - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> profileCC {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("one", forIndexPath: indexPath) as! profileCC

    // Configure the cell

    return cell
}



override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {

    switch kind {

    case UICollectionElementKindSectionHeader:

        let headerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "header", forIndexPath: indexPath) as! headerCell

        headerView.backgroundColor = UIColor.blueColor();
        return headerView

    case UICollectionElementKindSectionFooter:
        let footerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "footer", forIndexPath: indexPath) as! footerCell

        footerView.backgroundColor = UIColor.greenColor();
        return footerView

    default:

        assert(false, "Unexpected element kind")
    }
}

希望有人帮忙

您可以创建一个 UICollectionViewController 来处理 UICollectionView 并在 Interface Builder 中激活 FooterHeader sections,那么你可以使用下面的方法在你UICollectionView添加的两个sections中进行预览:

override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
    
    switch kind {
        
    case UICollectionView.elementKindSectionHeader:
        
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Header", for: indexPath)
        
        headerView.backgroundColor = UIColor.blue
        return headerView
        
    case UICollectionView.elementKindSectionFooter:
        let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Footer", for: indexPath)
        
        footerView.backgroundColor = UIColor.green
        return footerView
        
    default:
        
        assert(false, "Unexpected element kind")
    }
}

在上面的代码中,我将页脚和页眉的identifier设置为HeaderFooter,例如,您可以随意设置。如果要创建自定义页眉或页脚,则需要为每个创建 UICollectionReusableView 的子类并根据需要对其进行自定义。

您可以在 Interface Builder 或代码中注册您的自定义页脚和页眉 类:

registerClass(myFooterViewClass, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "myFooterView")

已更新 Swift 3+

第 1 步:

在您的视图控制器 class 中,注册 class 以用作页眉、页脚或两者:

let collectionViewHeaderFooterReuseIdentifier = "MyHeaderFooterClass"

第 2 步:

如果使用 xib,请使用:

collectionView.register(UINib(nibName: collectionViewHeaderFooterReuseIdentifier bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier:collectionViewHeaderFooterReuseIdentifier)

collectionView.register(UINib(nibName: collectionViewHeaderFooterReuseIdentifier bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier:collectionViewHeaderFooterReuseIdentifier)

如果不使用 xib:

collectionView.register(MyHeaderFooterClass.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier)

collectionView.register(MyHeaderFooterClass.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier)

第 3 步:

创建自定义 header/footer class,实现如下所示:

import UIKit

class MyHeaderFooterClass: UICollectionReusableView {

 override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.purple

    // Customize here

 }

 required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

 }
}

第 4 步: 如果不使用 xib,请忽略

  • 创建一个新的空 xib:"File --> New File --> Empty".

  • 将其命名为 与 class 完全相同的名称。在这个例子中:"MyHeaderFooterClass"

  • 向 xib 添加一个集合可重用视图。
  • 单击该对象,select 身份检查器并将该对象的 class 更改为 "MyHeaderFooterClass"。

第 5 步: - 通过委托方法支持集合视图中的新单元格:

 func collectionView(_ collectionView: UICollectionView,
                    viewForSupplementaryElementOfKind kind: String,
                    at indexPath: IndexPath) -> UICollectionReusableView {

    switch kind {

    case UICollectionElementKindSectionHeader:
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier, for: indexPath)

        headerView.backgroundColor = UIColor.blue
        return headerView

    case UICollectionElementKindSectionFooter:
        let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: collectionViewHeaderFooterReuseIdentifier, for: indexPath)

        footerView.backgroundColor = UIColor.green
        return footerView

    default:
        assert(false, "Unexpected element kind")
    }
}

第 6 步: 处理大小/使其显示:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 180.0)
}
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
        return CGSize(width: 60.0, height: 30.0)
}

只是为了补充剩余的答案,不要忘记为您的header/footer视图分配space,否则collectionView:viewForSupplementaryElementOfKind:atIndexPath 不会被调用.

通过在您的 collectionView 数据源中实施 collectionView:layout:referenceSizeForHeaderInSection 来做到这一点。

解决方案

class CustomFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
        var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()

        for attributes in attributesForElementsInRect! {

            if !(attributes.representedElementKind == UICollectionElementKindSectionHeader
                || attributes.representedElementKind == UICollectionElementKindSectionFooter) {

                // cells will be customise here, but Header and Footer will have layout without changes.
            }

            newAttributesForElementsInRect.append(attributes)
        }

        return newAttributesForElementsInRect
    }
}


class YourViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let headerNib = UINib.init(nibName: "HeaderCell", bundle: nil)
        collectionView.register(headerNib, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderCell")

        let footerNib = UINib.init(nibName: "FooterCell", bundle: nil)
        collectionView.register(footerNib, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "FooterCell")
    }


    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

        switch kind {
        case UICollectionElementKindSectionHeader:
            let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
            return headerView
        case UICollectionElementKindSectionFooter:
            let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "FooterCell", for: indexPath) as! FooterCell
            return footerView
        default:
            return UICollectionReusableView()
        }
    }

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

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 25)
    }
}

使用@mobilecat 代码后,您应该使用此功能使页眉和页脚出现

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 180.0)
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
        return CGSize(width: 60.0, height: 30.0)
    }

请注意,您的 viewController 必须实现 UICollectionViewDelegateFlowLayout,否则将不会调用这些方法

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

}

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

}

除以上所有答案外

激活页脚和页眉部分

Select 你的 collection 然后 select 属性检查器并检查页脚和页眉部分

喜欢照片

如果您需要为页眉和页脚保留空白,请扩展 UICollectionViewDelegateFlowLayout 并使用此代码相应地设置页眉或页脚。

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let footerValue = 150
    let headerValue = 150
    collectionView.contentInset = UIEdgeInsets(top: headerValue, left: 0, bottom: footerValue, right: 0)
}

Xcode 11+ & iOS 13+

我正在使用 Xib 创建页眉和页脚视图

  1. 像这样为页眉和页脚创建一个 Xibs 和 Class 文件(与页脚相同 class)并同时为两者创建 xib 视图
class HeaderViewCV: UICollectionReusableView {

}
  1. 像这样注册 Xib Cells
collectionView.register(UINib(nibName: "HeaderViewCV", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderViewCV") //elementKindSectionFooter for footerview
  1. 页眉和页脚查看方法
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    
   switch kind {
                
   case UICollectionView.elementKindSectionHeader:
            let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderViewCV", for: indexPath)
            return headerView
            
    case UICollectionView.elementKindSectionFooter:
            let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "FooterViewCV", for: indexPath)
            return footerView
            
     default:
            assert(false, "Unexpected element kind")
    }
}
  1. 对于两者的视图高度方法
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    return CGSize(width: self.collectionView.frame.width, height: 55)
}


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
    return CGSize(width: self.collectionView.frame.width, height: 67)
}
  1. 已完成 CollectionView 中页眉和页脚的所有必要要求已准备就绪

按照@mobilecat 的详细回答,如果您使用组合集合视图,请在创建布局时添加这些行:

let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
let headerElement = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)

并将 headerElement 设置为您的部分,如下所示:

 let section = NSCollectionLayoutSection(group: group)
 section.boundarySupplementaryItems = [headerElement]

完整的代码片段是:

private func createCompositionalLayout() -> UICollectionViewCompositionalLayout {
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalHeight(1.0),
                                          heightDimension: .fractionalHeight(0.2))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)

    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                           heightDimension: .fractionalWidth(1.0))
    
    let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
    
    let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
    let headerElement = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)

    let section = NSCollectionLayoutSection(group: group)
    section.boundarySupplementaryItems = [headerElement]


    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
  }