Collapse/Expand HeaderView With Tabs Part1
when you want to create collapse/expand header view like Android, you can see many tutorials about it with one scrollView, In this tutorials, we create it but with two or more tabs.
1- Creating a design
we will create a project and call it “Expand-CollapseHeaderWithTabs” and open Main.storyboard
We will add UIView and collectionView.
1.1 Adding UIView
add UIView to storyboard “ViewController” and add Constraints [Top, Leading, Trailing, height] which height = 250 or any height you want.
1.2 Adding CollectionView:
adding collectionView at the bottom of UIView and add Constraints [Top, Leading, Trailing, Bottom] and make scroll Direction of collectionView is Horizontal and check on paging Enable.
Now open ViewController.swift and take objects from collectionView and height of UIView, then set delegate and dataSource of collection to self
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var heightView : NSLayoutConstraint!
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
}}extension ViewController : UICollectionViewDelegate ,
UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 2 // the number of tabs you want
} func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return UICollectionViewCell()
}
}
After that, we need to create Cells for collectionView
these cells are represented as tabs. We will create two Cells.
2- Creating Cells
we will be creating two cells, the first cell contains scrollView and second cell contains TableView
2.1- ScrollView Cell
In this cell, we will create stack view and add views in it and put stack view in ContainerView then add container in scrollView, you can replace stack with any views, it is just for simplified but the main Component is scrollView and container view
2.2- TableView Cell
In this cell, we just create tableView and add constraints [leading, top, trailing, bottom]
Now we need to register these cells in collectionView and set delegate and dataSource for tableView to self, and add the extension in viewController to implement functions for tableView. then make cell size equal width and height of collectionView.
So, ViewController will look like this
Don’t forget to implement UICollectionViewDelegateFlowLayout to add function sizeForItemAt.
The result will look like this.
add variables in ViewController to determine max and min hight for header
let headerViewMaxHeight : CGFloat = 250
let headerViewMinHeight : CGFloat = 50
Now inside function cellForItemAt set delegate for scrollView in CellScrollView
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellScroll", for: indexPath) as! CellScrollView
cell.scrollView.delegate = self
return cell
We need to implement UIScrollViewDelegate in viewController, so we Will add an extension for ViewController and implement function scrollViewDidScroll and add this code inside it
extension ViewController : UIScrollViewDelegate {func scrollViewDidScroll(_ scrollView: UIScrollView) {
let y: CGFloat = scrollView.contentOffset.y
guard let headerViewHeightConstraint = heightView else {return}
let newHeaderViewHeight: CGFloat =
headerViewHeightConstraint.constant - y
if newHeaderViewHeight > headerViewMaxHeight {
headerViewHeightConstraint.constant = headerViewMaxHeight
} else if newHeaderViewHeight <= headerViewMinHeight {
headerViewHeightConstraint.constant = headerViewMinHeight
} else {
headerViewHeightConstraint.constant = newHeaderViewHeight
scrollView.contentOffset.y = 0 // block scroll view
}
}
}
Note:
scrollViewDidScroll is called also in the delegate of tableView because tableView is inherited from scrollView
If you run the app you can see this behavior.
Oops
cells did not resize for collectionView, really I don’t know why this behavior appears but this happens because of flow layout and changing the height of the CollectionView, and we will solve this problem by creating “custom collectionView”
We will create a dictionary with the key is indexPath and value is LayoutAttribute, so in “prepare” function will get every indexPath in all sections, then add it as Key and value is layout attribute by function
layoutAttributesForItem(at indexPath: IndexPath)
In function layoutAttributesForElements We will set itemSize is the frame of collectionView to change the frame for the cell when size collectionView is changing and filter dictionary to get the intersection of frames in attributes with rect in parameter
Add custom FlowLayout to collectionView
And add this code In viewDidLoad
if let l = collectionView.collectionViewLayout as? ExpandableFlowLayout {
l.scrollDirection = .horizontal
}
If you run the app you should see a smooth scroll, like this
In the next part, we will see some cases with bugs and how to solve them.
link for part two
Thanks for Reading, Tap the 👏 button if you found this article useful!