ViewForSupplementaryElementOfKind not called on custom UICollectionViewLayout

I created a custom UICollectionViewLayout and I put it in my collection controller in a storyboard. I had no problems displaying elements / cells. My problem is that viewForSupplementaryElementOfKind is not called. I can’t understand why this is so. I tried to return to the default layout, and it is called, but I need my custom UICollectionViewLayout. I left NSLogs to check and viewForSupplementaryElementOfKind is not called.

Here is my MyCollectionViewController.m

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. viewArray = [NSMutableArray array]; //setup the delegate for vertical flow layout [(VerticalFlowLayout*)self.collectionViewLayout setDelegate:self]; //register the headers [self.collectionView registerNib:[ButtonHeaderCollectionReusableView nib] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[ButtonHeaderCollectionReusableView reusableID]]; //set the insets [self.collectionView setContentInset:UIEdgeInsetsMake(23, 5, 10, 5)]; } #pragma mark - CollectionView DataSource -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return [self.cardsArray count]; } -(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { NSLog(@"Number of Sections"); return 1; } -(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"Making Card"); CardCell *card = [collectionView dequeueReusableCellWithReuseIdentifier:@"CardCell" forIndexPath:indexPath]; // UILabel *cardLabel = [card viewWithTag:101]; // [cardLabel setText:[textArray objectAtIndex:[indexPath row]]]; return card; } -(UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { NSLog(@"Making Header"); UICollectionReusableView *reusableView = nil; /*[[UICollectionReusableView alloc] initWithFrame:CGRectMake(0, 0, 100, 75)];*/ // [reusableView setBackgroundColor:[UIColor blackColor]]; if (kind == UICollectionElementKindSectionHeader) { ButtonHeaderCollectionReusableView *headerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[ButtonHeaderCollectionReusableView reusableID] forIndexPath:indexPath]; return headerview; } // if (kind == UICollectionElementKindSectionFooter) { // UICollectionReusableView *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath]; // } return reusableView; } -(CGSize)collectionView:collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { return CGSizeMake(180.0f, 72.0f); } 

Now here is my MyFlowLayout.m

 -(id)initWithCoder:(NSCoder *)aDecoder { NSLog(@"Vertical Flow Layout init with coder"); if(self = [super initWithCoder:aDecoder]) { contentHeight = 0; cachedAttributes = [NSMutableArray array]; } return self; } -(void)prepareLayout { NSLog(@"Preparing Layout"); // [super prepareLayout]; contentWidth = CGRectGetWidth(self.collectionView.bounds) - (self.collectionView.contentInset.left + self.collectionView.contentInset.right); if([cachedAttributes count] == 0) { //compute for column width CGFloat columnWidth = contentWidth / NUMBER_OF_COLUMNS; NSMutableArray *xOffsets = [NSMutableArray array]; for(int i = 0; i < NUMBER_OF_COLUMNS; i++) { [xOffsets addObject:[NSNumber numberWithFloat:(i * columnWidth)]]; } //compute for height NSMutableArray *yOffsets = [NSMutableArray array]; for(int i = 0; i < NUMBER_OF_COLUMNS; i++) { [yOffsets addObject:[NSNumber numberWithFloat:75]]; } int column = 0; //loop through all the sections and items in the collectionview for(int i = 0; i < self.collectionView.numberOfSections; i++) { for(int j = 0; j < [self.collectionView numberOfItemsInSection:i]; j++) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:j inSection:i]; //time to do some frame calculation ///let start with the width CGFloat width = columnWidth - CELL_PADDING * 2; ///then the height CGFloat viewHeight = [self.delegate getViewHeightWithCollectionView:self.collectionView indexPath:indexPath withWidth:width]; CGFloat height = CELL_PADDING + viewHeight + /*textHeight +*/ CELL_PADDING; CGFloat xOffset = [[xOffsets objectAtIndex:column] floatValue]; CGFloat yOffset = [[yOffsets objectAtIndex:column] floatValue]; CGRect frame = CGRectMake(xOffset, yOffset, columnWidth, height); CGRect insetFrame = CGRectInset(frame, CELL_PADDING, CELL_PADDING); //now that computation is done we shall make the attributes UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; [attributes setFrame:insetFrame]; [cachedAttributes addObject:attributes]; //time to increment the height and the column contentHeight = MAX(contentHeight, CGRectGetMaxY(frame)); NSNumber *yOffSetColumn = [yOffsets objectAtIndex:column]; yOffSetColumn = [NSNumber numberWithFloat:([yOffSetColumn floatValue] + height)]; [yOffsets replaceObjectAtIndex:column withObject:yOffSetColumn]; NSLog(@"Content Height: %f yOffSetColumn: %@ == %@", contentHeight, yOffSetColumn, [yOffsets objectAtIndex:column]); column = column >= (NUMBER_OF_COLUMNS - 1) ? 0 : ++column; } } } } -(CGSize)collectionViewContentSize { // NSLog(@"Collection View Content Size"); return CGSizeMake(contentWidth, contentHeight + 75); } //called after preparelayout to determine which items are visible in the given rect -(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { NSMutableArray <UICollectionViewLayoutAttributes *> *layoutAttributes = [NSMutableArray array]; NSInteger sectionsCount = [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView]; NSLog(@"Sections count: %ld", (long)sectionsCount); for(int i = 0; i < sectionsCount; i++) { //for header UICollectionViewLayoutAttributes *headerAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:i]]; // if(CGRectIntersectsRect(headerAttributes.frame, rect)) { // NSLog(@"Adding Section Attribute"); [layoutAttributes addObject:headerAttributes]; // } for (UICollectionViewLayoutAttributes *attributes in cachedAttributes) { if(CGRectIntersectsRect(attributes.frame, rect)) { [layoutAttributes addObject:attributes]; } } // NSInteger itemsCount = [self.collectionView numberOfItemsInSection:i]; // for(int j = 0; j < itemsCount; j++) { // UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]]; // if(CGRectIntersectsRect(attributes.frame, rect)) { // [layoutAttributes addObject:attributes]; // } // } } return layoutAttributes; } //-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { // NSLog(@"Layout Attributes For Item: %ld %ld", [indexPath row], [indexPath section]); // // UICollectionViewLayoutAttributes *attributes = [cachedAttributes objectAtIndex:[indexPath row]]; // return attributes; //} -(UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath { NSLog(@"Layout Attributes For Header: %@ %ld %ld", elementKind, [indexPath row], [indexPath section]); UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; [attributes setFrame:CGRectMake(0, 0, contentWidth /*320*/, 75.0f)]; return attributes; 

}

As you can see in MyFlowLayout, there are things I tried, but still it did not call viewForSupplementaryElementOfKind. I tried to implement layoutAttributesForItemAtIndexPath since I have layoutAttributesForSupplementaryViewOfKind. I also tried using fixed numbers like 75 and 320, which you see to check if the header will be generated. The delegate you see is just for getting the height of the view.

Since I gave the title enough space for viewing and left NSLogs around and (UICollectionReusableView *) collectionView: (UICollectionView *) collectionView viewForSupplementaryElementOfKind: (NSString *) kind atIndexPath: (NSIndexPath *) indexPath is not called.

Here are some of them that I looked through and tried: https://stackoverflow.com/a/167015/button/questions/414011/ ... , but as you can see from the comment I included. It still didn't work.

Thanks for the help.

+8
ios objective-c uicollectionview uicollectionviewlayout uicollectionreusableview
source share
2 answers

I also had a problem with this, and my solution was to simply add attributes for the section in prepareLayout

 UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; attributes.frame = CGRectMake(0, 0, self.collectionView.frame.size.width, 100); [cachedAttributes addObject:attributes]; 
+5
source share

Add a default header size:

 collectionViewLayout.headerReferenceSize = CGSize(width, height) 

The default values ​​are (0, 0). This is why the title is not displayed.

OR

There is another way: implement the delegate method for UICollectionView:

 collectionView(_:layout:referenceSizeForFooterInSection:) 
+4
source share

All Articles