Reputation: 24426
Having two headers in UICollectionView?
I've got a UICollectionView which uses the flow layout, which also has a header and footer:
---------
| head |
---------
| A | B |
---------
| C | D |
---------
| foot |
---------
Occasionally, I'd like to have two headers, like so:
---------
| head1 |
---------
| head2 |
---------
| A | B |
---------
| C | D |
---------
| foot |
---------
I'm stuck on how to achieve this. The flow layout only appears to allow one head and one foot. How can I add a second header?
edit: I have also implemented sticky headers - http://blog.radi.ws/post/32905838158/sticky-headers-for-uicollectionview-using - but I only want the first header to be sticky. This is why I can't just include everything in one header.
Upvotes: 23
Views: 16571
Reputation: 349
Define your UICollectionViewCell which will be your Header view of kind UICollectionElementKindSectionHeader - In my case I have two headers - OfferHeaderCell and APRHeaderCell defined as below:
verticalCollectionView.register(UINib(nibName: "OfferHeaderCell", bundle: nil), forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: "OfferHeaderCell")
verticalCollectionView.register(UINib(nibName: "APRHeaderCell", bundle: nil), forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: "APRHeaderCell")
Go ahead and return a header for each section and then set the size of the section header to have a size of zero in this UICollectionViewDelegateFlowLayout function
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if(section==0) {
return CGSize.zero
} else if (section==1) {
return CGSize(width:collectionView.frame.size.width, height:133)
} else {
return CGSize(width:collectionView.frame.size.width, height:100)
}
}
Important to define the viewForSupplementaryElementOfKind for two different sections as below:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var reusableview = UICollectionReusableView()
if (kind == UICollectionElementKindSectionHeader) {
let section = indexPath.section
switch (section) {
case 1:
let firstheader: OfferHeaderCell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "OfferHeaderCell", for: indexPath) as! OfferHeaderCell
reusableview = firstheader
case 2:
let secondHeader: APRHeaderCell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "APRHeaderCell", for: indexPath) as! APRHeaderCell
reusableview = secondHeader
default:
return reusableview
}
}
return reusableview
}
And lastly the Datasource,
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (section==2) {
return 2
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = verticalCollectionView.dequeueReusableCell(withReuseIdentifier: "ReviseOfferCell", for: indexPath)
cell.backgroundColor = UIColor.white
return cell
}
Note: Don't forgot to add UICollectionFlowLayout as below:
// MARK: UICollectionViewDelegateFlowLayout
extension MakeAnOfferController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item == 0 {
return CGSize(width: self.view.frame.size.width, height: 626.0)
}
return CGSize()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if(section==0) {
return CGSize.zero
} else if (section==1) {
return CGSize(width:collectionView.frame.size.width, height:133)
} else {
return CGSize(width:collectionView.frame.size.width, height:100)
}
}
}
Upvotes: 2
Reputation: 1735
Got this working by creating two views in a reusable header, implement sticky header only if the section is the second section. Also, I adjust the numberOfSection to 2. Got the headers switching by hiding and showing the views in viewForSupplementaryElementOfKind.
Upvotes: 0
Reputation: 12641
You just need to use a simple trick.Show header and footer both for all sections.
In which section you do not want to show footer just pass its size zero as :--
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
{
if(section==0)
{
return CGSizeZero;
}
return CGSizeMake(320, 50);
}
Here I have used two sections like
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 2;
}
And passed no of rows in only one sections that is the last one as
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (section==1) {
return 20;
}
return 0;
}
And here is my output ---
Red View is header and Green One is footer.
Here u can get the entire Implementation File
Upvotes: 35
Reputation: 2024
What you can do is use a UITableView with two sections and put the UICollectionView in the cell of the second section.
Upvotes: 2
Reputation: 6427
This content may help you to achieve what you want
create the class CollectionHeaderView
and make it to derive from UICollectionReusableView
and make container, And then after make 2 uiview and put it to this container
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *reusableview = nil;
if (kind == UICollectionElementKindSectionHeader) {
CollectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];
headerView.firstContainer.titleLabel.text = @"MY Header View 1";//Here you can set title
headerView.secondContainer.titleLabel.text = @"MY Header View 2";//Here you can set title
UIImage *headerImage = [UIImage imageNamed:@"header_banner.png"];
headerView.firstContainer.backgroundImage.image = headerImage;
headerView.secondContainer.backgroundImage.image = headerImage;
reusableview = headerView;
}
if (kind == UICollectionElementKindSectionFooter) {
UICollectionReusableView *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath];
reusableview = footerview;
}
return reusableview;
}
Upvotes: 5
Reputation: 6969
How are you adding one header? I suppose by specifying section headers? The recipe to have two headers would be to have two header subviews inside one header main view.
Upvotes: 2
Reputation: 69469
You should put both the header (1 and 2) in an other view and place that view as head 1. Thus create just on header in the collection view.
Upvotes: 4