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

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.

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

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

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

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.

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

Xcode 11+ & iOS 13+
I am using Xib for creating Header & Footer Views
Create a Xibs and Class File For Header & Footer like this (Same as Footer class) & also create xib views for both
class HeaderViewCV: UICollectionReusableView {
}
Register Xib Cells like this
collectionView.register(UINib(nibName: "HeaderViewCV", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderViewCV") //elementKindSectionFooter for footerview
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")
}
}
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)
}
Done all the necessary requirement for Header & Footer in CollectionView is ready

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

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

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

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
}

Related

Spacing between the cells as per the label width in horizontal CollectionView in case of 2 rows

As shown above,I want two fixed horizontal rows, with labels width according text and spacing between cells same as I’m getting in a single row.
(Please refer Image Url)
I’m unable to achieve the same in case of two horizontal rows.
I used CollectionView for doing it, but no luck.
var dataArray = ["1A-Label", "2B-Label here", "3Chhhh", "4D-Label here", "5E-La here*","6F-Label here B-Label", "7G-Label", "8H-Label here", "9I- here", "10J-Label here", "11K-Label here------", "12L-Label here", "13M-Label here", "14N-Label here", "15O-Label here", "16P-Label here", "17Q-Label here------", "18R-Label here", "19S-Label here"]
let headerIdentifier = "HeaderView"
let headerName = "FilterCustomCollectionReusableView"
let brandCellIdentifier = "brandFilterCell"
let brandCellName = "BrandFilterCollectionViewCell"
override func viewDidLoad() {
super.viewDidLoad()
baseCollectionView.register(UINib(nibName: headerName, bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifier)
baseCollectionView.register(UINib(nibName: brandCellName, bundle: nil), forCellWithReuseIdentifier: brandCellIdentifier)
baseCollectionView.delegate = self
baseCollectionView.dataSource = self
collectionViewHeight.constant = 90
if let flowLayout = self.baseCollectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = CGSize(width: 1, height: 1)
}
}
//MARK:- Collection Functions
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: brandCellIdentifier, for: indexPath) as! BrandFilterCollectionViewCell
cell.configureBrandCell(labelText: dataArray[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionView.elementKindSectionHeader:
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath)
return headerView
default:
assert(false, "Unexpected element kind")
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: 100, height: baseCollectionView.frame.height)
}
Any help is greatly appreciated.
Thanks in advance for the help.

Header not showing in UICollectionViewController Swift

I am trying to add a header to my UICollectionViewController. I have done this all through storyboard. When I run the app it doesn't show up.
This is what I am trying to display in my header:
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "Header", forIndexPath: indexPath) as! ProfileCollectionReusableView
header.editProfileButton.layer.cornerRadius = 5
header.nameLabel.adjustsFontSizeToFitWidth = true
header.nameLabel.text = PFUser.currentUser()!["name"] as? String
header.profilePictureImageView.layer.cornerRadius = header.profilePictureImageView.frame.size.height/2
header.profilePictureImageView.layer.masksToBounds = true
header.profilePictureImageView.layer.borderColor = UIColor.whiteColor().CGColor
return header
}
I am not seeing any errors on the console nor does the app crash. There is just a white screen with the navigation bars title updated to the users username.
if use .xib
let nib1:UINib = UINib(nibName: "ScheduleHeaderView", bundle: nil)
self.myCollection.register(nib1, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "ScheduleHeaderView")
set size for header
let layout = self.myCollection.collectionViewLayout as! UICollectionViewFlowLayout
layout.headerReferenceSize = CGSize(width: 50, height: 180)
UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header:ScheduleHeaderView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "ScheduleHeaderView", for: indexPath) as! ScheduleHeaderView
return header
}
Here are some tips you need to pay attention to what you have to do:
1.Implement UICollectionViewDelegateFlowLayout like:
class MyCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {}
2.register header class before you use :
self.collectionView!.registerClass(HeaderClass.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header")
in the method ViewDidLoad();
3.set the size in the UICollectionViewDelegateFlowLayout like UITableViewDelegate
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSizeMake(Config.PHONE_WIDTH, 55)
}
4.return your own header like what you already done:
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
}
The issue could very well be with the height of the header section. I encountered the similar issue where I was registering the header but then the height was not set.
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 20, height: 20)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.white //default background color is black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.register(Header.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderCell")
//setting the height helped it in displaying on the page
layout.headerReferenceSize = CGSize(width: 50, height: 180)
To show header just make sure you have this code in your code with number "1", like this:
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}

How to add header and footer view of UICollectionView in Swift

I have added the delegate function in the controller class but it won't called at the run time.
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
}
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! UICollectionReusableView
headerView.backgroundColor = UIColor.blueColor();
return headerView
case UICollectionElementKindSectionFooter:
let footerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "Footer", forIndexPath: indexPath) as! UICollectionReusableView
footerView.backgroundColor = UIColor.greenColor();
return footerView
default:
assert(false, "Unexpected element kind")
}
}
I follow this tutorial Appcoda tutorial and update code For swift 4.0
Register the class :
self.collectionView.register(HeadView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeadView")
Delegates :
// For header size (required)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width:collectionView.frame.size.width, height:50.0)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeadView", for: indexPath)
headerView.backgroundColor = UIColor.blue;
return headerView
default:
fatalError("Unexpected element kind")
}
}
Delegate method not called because you need to register a class for the supplementary view;
yourCollectionView.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "collectionHeaderID")
yourCollectionView.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "collectionFooterID")
If you use Custom UICollectionViewFlowLayout
set headerReferenceSize
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .vertical
flowLayout.minimumLineSpacing = 0
flowLayout.minimumInteritemSpacing = 0
flowLayout.sectionHeadersPinToVisibleBounds = true
flowLayout.headerReferenceSize = CGSize(width: self.collectionView.frame.size.width, height: 50)

Header not showing up in UICollectionView even already registered programmatically in UICollectionViewFlowLayout

My header seems not showing up even I already registered programmatically in UICollectionViewFlowLayout. Just blank.
My code
override func viewDidLoad() {
super.viewDidLoad()
UICollectionReusableViewlet layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: 117, height: 117)
layout.minimumLineSpacing = 1
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.registerClass(EventHeaderView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: "MyHeaderView");
collectionView!.registerClass(EventDetailCollectionViewCell.self, forCellWithReuseIdentifier:"MyCollectionViewCell")
collectionView!.backgroundColor = UIColor.blackColor()
self.view.addSubview(collectionView!)
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
switch kind {
//2
case UICollectionElementKindSectionHeader:
//3
let headerView =
collectionView.dequeueReusableSupplementaryViewOfKind(kind,
withReuseIdentifier: "HeaderView",
forIndexPath: indexPath)
as! EventHeaderView
headerView.lblName.text = "Anniversary"
headerView.lblDescription.text = "Venue"
return headerView
default:
//4
assert(false, "Unexpected element kind")
}
}
Digging deeper from Ryan Lee's answer:
public func collectionView(_:UICollectionView, layout: UICollectionViewLayout, referenceSizeForHeaderInSection: Int) -> CGSize
{
if referenceSizeForHeaderInSection > 0 {
return CGSize.zero
}
return CGSize(width:0, height:50)
}
in case you have headers only for some sections, but not all of them
Assign datasource, delegate from UICollectionView to UIViewController.
Add custom UICollectionView class and assign it to UICollectionViewCell in storyboard. Also assign an identifier.
Set section header in inspector. (Image)
A header cell will be generated in collection view. Add another UICollectionViewCell class and assign this class to that cell. Also set an identifier.
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return 9
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("customCell", forIndexPath: indexPath) as! CustomCollectionViewCell
cell.counterLabel.text = "\(indexPath.item)"
return cell
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
let headerView =
collectionView.dequeueReusableSupplementaryViewOfKind(kind,withReuseIdentifier: "headerCell", forIndexPath: indexPath) as! HeaderCollectionViewCell
return headerView
default:
assert(false, "Unexpected element kind")
}
}
Here is link to github project.
Make sure you add this line in the layout:
layout.headerReferenceSize = CGSize(width:0, height:50)

UICollectionView AutoSize header height

I'm coding for iOS 8+.
I have a UICollectionReusableView that's being used as header of UICollectionView
class UserHeader: UICollectionReusableView {
...
}
My View Collection does a few things:
Loads NIB in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
resultsCollectionView.registerNib(UINib(nibName: "UserHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "UserHeader")
}
Sets header height in referenceSizeForHeaderInSection.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSizeMake(0, 500)
}
However, my UserHeader view comprised of many UILabel, UIViews who's height changes at run time, how can I specify a height for referenceSizeForHeaderInSection that's dynamic? Or if I'm not supposed to use referenceSizeForHeaderInSection for auto-sizing in iOS 8+, please let me know what I should use. Thanks in advance.
For completeness sake, here's how I load the view, but I'm not sure if that's relevant for this discussion:
func collectionView(collectionView: UICollectionView!, viewForSupplementaryElementOfKind kind: String!, atIndexPath indexPath: NSIndexPath!) -> UICollectionReusableView! {
var reusableview:UICollectionReusableView = UICollectionReusableView()
if (kind == UICollectionElementKindSectionHeader) {
let userHeaderView = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "UserHeader", forIndexPath: indexPath) as! UserHeader
... extra code to modify UserHeader
reusableview = userHeaderView
}
return reusableview
}
I faced a similar issue and fixed it by using NSLayoutConstraints within the view to specify the height of the header view. Within the view controller I then configure the collection view's header thusly:
fileprivate var expectedSectionHeaderFrame = CGRect.zero
let headerIdentifier = "HeaderView"
func calculateHeaderFrame() -> CGRect {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let expectedHeaderSize = CGSize(width: view.bounds.width, height: headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height)
return CGRect(origin: .zero, size: expectedHeaderSize)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
expectedSectionHeaderFrame = calculateHeaderFrame()
return expectedSectionHeaderFrame.size
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
guard kind == UICollectionElementKindSectionHeader else { fatalError("Unexpected kind of supplementary view in (type(of: self))") }
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath)
headerView.frame = expectedSectionHeaderFrame
return headerView
}

Resources