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

IosSwiftUicollectionview

Ios Problem Overview


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

I'm trying to combine a header and a footer together but it keep crashing, I couldn't find swift tutorial to understand it.

I don't how to return supplementary view for both rather just one .

I set them both on the storyboard (class + identifier )

 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")
    }
}

I hope someone will help.

Ios Solutions


Solution 1 - Ios

You can make an UICollectionViewController to handle the UICollectionView and in Interface Builder activate the Footer and Header sections, then you can use the following method for preview in you UICollectionView the two sections added :

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")
    }
}

In the above code I put the identifier for the footer and header as Header and Footer for example, you can do it as you want. If you want to create a custom header or footer then you need to create a subclass of UICollectionReusableView for each and customize it as you want.

You can register your custom footer and header classes in Interface Builder or in code with:

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

Solution 2 - Ios

Updated for Swift 3+

Step 1:

In your view controller class, register the class to be used as a header, footer, or both:

let collectionViewHeaderFooterReuseIdentifier = "MyHeaderFooterClass"

Step 2:

If using a xib, use:

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

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

If not using a xib:

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

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

Step 3:

Create a custom header/footer class, implementation looks like:

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)
    
 }
}

Step 4: If not using a xib, ignore

  • Create a new empty xib: "File --> New File --> Empty".

  • Name it the exact same name as the class. In this example: "MyHeaderFooterClass"

  • Add a collection reusable view to the xib.

  • Click on that object, select the Identity Inspector and change the class of that object to "MyHeaderFooterClass".

Step 5:

  • Support that new cell in your collection view via delegate method:

    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")
      }
    

    }

Step 6: Handle size / make it appear:

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)
}

Solution 3 - Ios

In addition to all answers above

To activate the Footer and Header sections

Select your collection then select Attributes inspector and check on the Footer and Header sections

like in photo

enter image description here

Solution 4 - Ios

Just to complement the remaining answers, don't forget to allocate space for your header/footer views, otherwise collectionView:viewForSupplementaryElementOfKind:atIndexPath won't be called.

Do so by implementing collectionView:layout:referenceSizeForHeaderInSection in your collectionView datasource.

Solution 5 - Ios

After using @mobilecat code you should use this function to make the header and footer appear

 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)
    }

Solution 6 - Ios

Xcode 11+ & iOS 13+

I am using Xib for creating Header & Footer Views

  1. Create a Xibs and Class File For Header & Footer like this (Same as Footer class) & also create xib views for both
class HeaderViewCV: UICollectionReusableView {

}
  1. Register Xib Cells like this
collectionView.register(UINib(nibName: "HeaderViewCV", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderViewCV") //elementKindSectionFooter for footerview
  1. Header & Footer View Methods
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. For View Height Method for both
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. Done all the necessary requirement for Header & Footer in CollectionView is ready

Solution 7 - Ios

Solution

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)
    }
}

Solution 8 - Ios

if you need to keep empty spaces for header and footer make an extension of UICollectionViewDelegateFlowLayout and use this code to set header or footer accordingly.

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

Solution 9 - Ios

Note that your viewController must implement UICollectionViewDelegateFlowLayout or these methods won't get called

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

}

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

}

Solution 10 - Ios

following @mobilecat detailed answer, if you are using compositional collection view, add these lines when creating the layout:

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

and set the headerElement to your section like this:

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

The full code snippet is:

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
  }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmarrioaView Question on Stackoverflow
Solution 1 - IosVictor SiglerView Answer on Stackoverflow
Solution 2 - IosmobilecatView Answer on Stackoverflow
Solution 3 - IosGerges EidView Answer on Stackoverflow
Solution 4 - IosBruno CunhaView Answer on Stackoverflow
Solution 5 - IosAhmed AbdallahView Answer on Stackoverflow
Solution 6 - IosThreadripperView Answer on Stackoverflow
Solution 7 - IosZanaelView Answer on Stackoverflow
Solution 8 - IosPramodya AbeysingheView Answer on Stackoverflow
Solution 9 - IosCarlos Perez PerezView Answer on Stackoverflow
Solution 10 - IosnivbpView Answer on Stackoverflow