Stretchable Header view in UICollectionView— Swift 5, iOS

ANANTHA KRISHNAN K G
4 min readJun 25, 2019

--

This is the stretchable header series 3rd part. Checkout the previous parts here,

  1. Stretchable header in ScrollView
  2. Stretchable header in TableView

Today let’s talk about how to add a stretchable ImageView header in the UICollectionView like this,

First we have to create a collection view with a cell size of 160 (width & height), I have added the cell identifier as `stCCell` . Then add `dataSource` as `self` to the Collectionview outlets inside the `viewController`. Then add the `UICollectionViewDataSource`methods like this ,

extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "stCCell", for: indexPath) as UICollectionViewCell

cell.backgroundColor = .red
cell.layer.cornerRadius = 10.0
return cell
}

This will give to a collection view with 20 cells.

Now its time to add our header View. For this , go to the storyboard and drag and drop a `UICollectionReusableView` to the collectionView.

Set the height of the `UICollectionReusableView` to 250 . Now drag and drop an imageview to the header view.

Next is to create a custom `UICollectionReusableView` and name it as `STCollectionReusableView`. Then link the header view in storyboard to the new custom class. Create a reference to the image View.

Now the we have to change some code inside the UICollectionViewFlowLayout class. Create a custom UICollectionViewFlowLayout class and link the story board collection view layout to the custom class.

Now even if you run the app, the header view wont show up. For the header view to come up , we have to add the view in `viewForSupplementaryElementOfKind` of the `UICollectionViewDataSource`. Add the below code to your app,

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

switch kind {
case UICollectionView.elementKindSectionHeader:
guard
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "stCHeadCell", for: indexPath) as? STCollectionReusableView else {
fatalError("Invalid view type")
}

headerView.imgView.image = #imageLiteral(resourceName: "img")
return headerView
default:
assert(false, "Invalid element type")
}
}

by running the application now , you will be able to see the header. But still the stretchy part wont work.

To make the header stretchable , we need to override the implementation of two `UICollectionViewFlowLayout`. Go to our custom `UICollectionViewFlowLayout` class and add the following method first,

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

For more details see this Apple Doc

Now comes the fun part. The Flowlayout class has a method named `layoutAttributesForElements`, which holds attributes of each views in a specified rectangle. Here we have to check two things

  1. Whether the user is scrolling up, that means the header should become stretchy.
  2. Check whether the element is a header element view. If so change the height and y position of the headerView.

See the below code,

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

let layoutAttributes = super.layoutAttributesForElements(in: rect)

guard let offset = collectionView?.contentOffset, let stLayoutAttributes = layoutAttributes else {
return layoutAttributes
}
if offset.y < 0 {

for attributes in stLayoutAttributes {

if let elmKind = attributes.representedElementKind, elmKind == UICollectionView.elementKindSectionHeader {

let diffValue = abs(offset.y)
var frame = attributes.frame
frame.size.height = max(0, headerReferenceSize.height + diffValue)
frame.origin.y = frame.minY - diffValue
attributes.frame = frame
}
}
}
return layoutAttributes
}

After adding the code run the app, you will be able to see the stretchy header.

That’s it . Now you know how to add a stretchy header in collectionView. Get the source code from here.

If you enjoyed reading this post, please share and recommend it so others can find it 👍👍 !!!!

You can follow me on Medium for fresh articles. Connect with me on LinkedIn and GitHub.

--

--