I have a UICollectionView in one of my viewcontroller. My collection view uses a subclass of UICollectionViewLayout (custom) to layout the cells. First thing, as soon as I select Layout as Custom in dropdown on Storyboard, option to select supplementary views goes away.
I tried doing that programatically as shown below, but none of the delegate methods are getting called.
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
if (kind == UICollectionElementKindSectionHeader) {
UICollectionReusableView *reusableview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView" forIndexPath:indexPath];
if (reusableview==nil) {
reusableview=[[UICollectionReusableView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
}
UILabel *label=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
label.text=[NSString stringWithFormat:#"Recipe Group #%li", indexPath.section + 1];
[reusableview addSubview:label];
return reusableview;
}
return nil;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
CGSize headerSize = CGSizeMake(320, 44);
return headerSize;
}
In my viewDidLoad Method I have
[self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView"];
Can anyone point me where I'm messing up?
You're passing in the incorrect view kind.
Your line registering the class:
[self.collectionView registerClass:[UICollectionReusableView class]
forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
withReuseIdentifier:#"HeaderView"];
Should be:
[self.collectionView registerClass:[UICollectionReusableView class]
forSupplementaryViewOfKind: UICollectionElementKindSectionHeader
withReuseIdentifier:#"HeaderView"];
Edit: Looks like your code is all using sectionFooter. Are you trying to programmatically add a header or a footer?
Found the issue, I was not returning attributes of my header in this UICollectionLayoutView method:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect
Check that you gave reference size for header in UICollectionViewFlowLayout
[flowLayout setHeaderReferenceSize:CGSizeMake(320, 50)];
and for footer
[flowLayout setFooterReferenceSize:CGSizeMake(320, 50)];
Your delegate method for header reference size is wrong, you call footer method,referenceSizeForFooterInSection, as follow:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
CGSize headerSize = CGSizeMake(320, 44);
return headerSize;
}
Individually set HeaderReferenceSize will fix the header problem. But app will crash you keep the above method and return nil in viewForSupplementaryElementOfKind for Footer.
your check:
if (kind == UICollectionElementKindSectionFooter)
Your should check for: UICollectionElementKindSectionHeader
same for:
dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
I think you should call this in your viewdidload method:
[collectionViewFlowLayout setHeaderReferenceSize:CGSizeMake(self.collectionView.frame.size.width, 50)];
Related
I have a ViewController that contain a CollectionView :
- (void)viewDidLoad
{
UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
collectionview = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout];
collectionview.backgroundColor = [UIColor colorWithRed:0.86 green:0.86 blue:0.86 alpha:1.0];
collectionview.translatesAutoresizingMaskIntoConstraints = false;
collectionview.delegate = self;
collectionview.dataSource = self;
collectionview.bounces = true;
[collectionview registerClass:[CollectionViewCell1 class] forCellWithReuseIdentifier:#"cell1"];
[self.view addSubview:collectionview];
[collectionview sdc_alignEdgesWithSuperview:UIRectEdgeAll];
[collectionview registerClass:[RecipeCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView"];
}
-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *reusableview = nil;
RecipeCollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView" forIndexPath:indexPath];
headerView.backgroundColor = [UIColor greenColor];
headerView.title.text = #"ABC";
reusableview = headerView;
return reusableview;
}
and RecipeCollectionReusableView is :
- (void)initialize
{
_title = [UILabel new];
_title.translatesAutoresizingMaskIntoConstraints = false;
[self addSubview:_title];
[_title sdc_centerInSuperview];
}
but there isn't any header on the screen after run.
Did you do the required implementation for the header?
https://developer.apple.com/documentation/uikit/uicollectionviewdelegateflowlayout/1617702-collectionview?language=objc
collectionView:layout:referenceSizeForHeaderInSection:
Return Value
The size of the header. If you return a value of size (0, 0), no header is added.
Discussion
If you do not implement this method, the flow layout uses the value in its
headerReferenceSize
property to set the size of the header.
During layout, only the size that corresponds to the appropriate scrolling direction is used. For example, for the vertical scrolling direction, the layout object uses the height value returned by your method. (In that instance, the width of the header would be set to the width of the collection view.) If the size in the appropriate scrolling dimension is 0, no header is added.
This article completely helped me :
How to add Header wit Supplementary view to UiCollectionView in Objective-C
I am implementing a header for my UICollectionView right now, and I am struggling right now since the header is called only once on the first cell.
This is what I've done - I declared UICollectionViewFlowLayout to programmatically make a UICollectionView - in this case, pickView. And then I added two xib files - one for cell, and the other one for header. I have registered those files into collection view like this:
UICollectionViewFlowLayout *layout2 = [[UICollectionViewFlowLayout alloc] init];
self.pickView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, pointView_y, pointView_width, pointView_length) collectionViewLayout:layout2];
self.pickView.backgroundColor = [UIColor whiteColor];
[self.pickView registerNib:[UINib nibWithNibName:#"TodayCollectionViewCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:#"TodayCollectionViewCell"];
[self.pickView registerNib:[UINib nibWithNibName:#"PickCollectionReusableView" bundle:[NSBundle mainBundle]] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"PickCollectionReusableView"];
//layout2.headerReferenceSize = CGSizeMake(_screenWidth, 50);
[self.pickView setDataSource:self];
[self.pickView setDelegate:self];
[self.view addSubview:self.pickView];
And then I declared the size of header view like this:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
return CGSizeMake([Util screenWidth], 50);
}
And finally I called viewForSupplementaryElementOfKind to call header files like this:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
PickCollectionReusableView *reusableview = (PickCollectionReusableView*) [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"PickCollectionReusableView" forIndexPath:indexPath];
PickCellVariable *buf = (PickCellVariable*) _pickArray[indexPath.row];
NSLog(#"buf id = %#, SECTION = %lu", buf.itemID, (long)indexPath.row);
if(buf != nil) {
//reusableview.thumbPic = ;
[reusableview.brandName setTitle:[NSString stringWithFormat:#"%lu", (long)indexPath.row] forState:UIControlStateNormal];
[[reusableview brandName] setBrandName:buf.brandname];
[[reusableview brandName] addTarget:self action:#selector(brandClick:) forControlEvents:UIControlEventTouchUpInside];
[[reusableview settingButton] addTarget:self action:#selector(setting:) forControlEvents:UIControlEventTouchUpInside];
return reusableview;
}
else {
[[reusableview brandName] setBrandName:#""];
return reusableview;
}
}
I put the breakpoint and added NSLog line to make sure that viewForSupplementaryElementOfKind is only called once, in the very first cell.
I've tried to find cases like mine, but most of the issues regarding the UICollectionView header is when they registered class instead of registering xib file, or they forgot to set the size of header view. Mine is only called for once so this is not about overlap as well. My collection view is programmatically made so I do not redefine anything right now.
What could be the issue? Please, anything can help in here.
Thank you.
Ok, so my problem was that I called my data on row basis. However, in order to make header to appear on every cell, you have to call your data in section basis.
I hope no one is struggling anymore like me in terms of this issue.
I am trying show footer on collection view. In my story board i set accessory as footer in UICollectionView and i took collection reusable view.
[self.cv registerClass:[ItemFooterView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView"];//in view did load
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
ItemFooterView *footerView=[collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView" forIndexPath:indexPath];
return footerView;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
{
return CGSizeMake(50, 50);
}
still footer not showing if any suggestions on this.
UICollectionViewLayout *layout = [[UICollectionViewLayout alloc] init];
layout.footerReferenceSize = CGSizeMake(300, 60);
make sure you have set the size for the footer
I think you forgot to register class/nib for the footer view. Do this in viewDidLoad
[self.collectionView registerClass:[FooterView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView"];
This is a duplicate of this question. I'm asking again because the accepted answer is not working and no one's providing more explanation on how the supposed correct answer works.
So here's the situation: I want to display the collection view into one single row. To do this, I applied a custom UICollectionViewFlowLayout to the collection view and set the scrolling to horizontal. Everything is working fine, except for section header disappeared.
To remedy this, I implemented this function:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(350, 35);
}
Now the header is shown, but the problem is it is displayed to the left of the cells, instead of the usual top.
I stumbled upon the link above while searching for a solution, but like I've said, the accepted answer is not working at all and I could not find other solutions about this situation. So can anyone help me here?
we can do that by using the delegate method -
(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
and keeping the left inset to minus value of width of supplementary view and managing the top inset
Have you tried using the header with something like this?
First: set it up in viewDidLoad...
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.headerReferenceSize = CGSizeMake(self.collectionView.bounds.size.width, 30);
// add any other setup you need
[self.collectionView setCollectionViewLayout:flowLayout];
Second: add header view ...
#define LABEL_TAG 128
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:
UICollectionElementKindSectionHeader withReuseIdentifier:#"SectionHeader" forIndexPath:indexPath];
UILabel *label = (UILabel *)[headerView viewWithTag:LABEL_TAG];
if (!label) {
label = [[UILabel alloc] initWithFrame:CGRectInset(headerView.bounds, 5, 5)];
label.tag = MY_HEADER_LABEL_TAG;
label.font = [UIFont boldSystemFontOfSize:12];
label.textColor = [UIColor redColor];
[headerView addSubview:label];
}
label.text = [NSString stringWithFormat:#"Section %d", indexPath.section];
return headerView;
}
I have a Collection View and has custom cells with images and labels in there. I have set my collection view as follows -
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
flowLayout.minimumLineSpacing = 150.0f;
flowLayout.minimumInteritemSpacing = 104.0f;
flowLayout.sectionInset = UIEdgeInsetsMake(20, 20, 100, 120);
_archiveCollectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_archiveCollectionView.frame = CGRectMake(30, 218, _archiveCollectionView.frame.size.width - 60, _archiveCollectionView.frame.size.height - 350);
_archiveCollectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_archiveCollectionView.backgroundColor = [UIColor clearColor];
_archiveCollectionView.delegate = self;
_archiveCollectionView.dataSource = self;
[self.archiveCollectionView registerNib:[UINib nibWithNibName:#"FullArchiveEditionCell" bundle:nil] forCellWithReuseIdentifier:#"MyCell"];
[_archiveCollectionView reloadData];
[self.view addSubview:_archiveCollectionView];
I have also set the following methods:
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _chosenCategoryArray.count;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self addEditionsChildView];
}
-(BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
However, my didSelectItemAtIndexPath never gets called when I select a cell. Any help please?
I had a similar problem and it turned out I was using the same cell reuse identifier in two different collection views
In your header file have you implemented UICollectionViewDelegate as like below,
#interface HAViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate>
I have the same problem. And I solved by using storyboard to locate the collection cell in the collection view controller. Then tick User InterAction Enabled. I think using code to set in the UICollectionViewCell would also work. Hope it would help.
Try with changing sequence as given below
[_archiveCollectionView reloadData];
[self.view addSubview:_archiveCollectionView];
to
[self.view addSubview:_archiveCollectionView];
[_archiveCollectionView reloadData];
Implement the below delegate method.
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}
And implement your
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
//your selection management code
}
and
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
//deselection handling code
}