JJCollectionViewRoundFlowLayout Custom Section Header and Footer Calculation
JJCollectionViewRoundFlowLayout calculates section header and footer frames by querying supplementary view attributes, merging them with cell frames using CGRectUnion, and applying custom border insets to generate rounded background decoration views.
The kingjiajie/jjcollectionviewroundflowlayout repository extends UICollectionViewFlowLayout to draw rounded backgrounds behind collection view sections. Understanding JJCollectionViewRoundFlowLayout custom section header and footer calculation is essential for creating polished section backgrounds that properly encompass headers, footers, and cells while handling edge cases like empty sections and irregular cell sizes.
How Header and Footer Frames Are Calculated
Collecting Section Information
In JJCollectionViewRoundFlowLayout.m, the ‑prepareLayout method iterates over every section using a standard for loop: for (NSInteger section = 0; section < sections; section++). For each section, the layout determines geometry by first obtaining the first and last item frames via layoutAttributesForItemAtIndexPath:. If the section is empty, the delegate method collectionView:layout:isCanCalculateWhenRowEmptyWithSection: (or the property isCanCalculateWhenRowEmpty) determines whether processing continues.
Header Detection and Frame Calculation
The layout first evaluates the isCalculateHeader property. However, the delegate can override this per section:
BOOL isCalculateHeaderView = self.isCalculateHeader;
if ([delegate respondsToSelector:@selector(collectionView:layout:isCalculateHeaderViewIndex:)]) {
isCalculateHeaderView = [delegate collectionView:self.collectionView layout:self isCalculateHeaderViewIndex:section];
}
When isCalculateHeaderView is YES, the layout fetches attributes via layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader. If a header exists, its frame becomes the firstFrame; otherwise, the layout uses the first cell's frame. For sections with irregularly sized cells, enabling isCalculateTypeOpenIrregularitiesCell triggers calculateIrregularitiesCellByMinTopFrameWithLayout: to ensure the background covers all cells regardless of size variations.
Footer Detection and Frame Calculation
The footer follows an identical pattern using isCalculateFooter, collectionView:layout:isCalculateFooterViewIndex:, and layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter. The resulting footer frame serves as the lastFrame, or the layout falls back to the last cell. When handling irregular layouts, calculateIrregularitiesCellByMaxBottomFrameWithLayout: expands the frame to include the bottom-most cells.
Merging Frames and Applying Insets
The layout unites the header and footer frames using CGRectUnion(firstFrame, lastFrame) to create the section content rectangle. It then applies two types of insets:
- Standard section insets from
JJCollectionViewFlowLayoutUtils evaluatedSectionInsetForItemWithCollectionLayout: - Custom border insets provided by the delegate via
collectionView:layout:borderEdgeInsertsForSectionAtIndex:
These insets are added to the calculated rectangle and stored in the decoration attributes' borderEdgeInsets property. The final JJCollectionViewRoundLayoutAttributes object receives the section frame, zIndex of -1 (to appear behind cells), and a myConfigModel instance containing visual styling parameters.
JJCollectionViewRoundLayoutAttributes *attr = [JJCollectionViewRoundLayoutAttributes
layoutAttributesForDecorationViewOfKind:JJCollectionViewRoundSection
withIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
attr.frame = sectionFrame;
attr.zIndex = -1;
attr.borderEdgeInsets = userCustomSectionInset;
attr.myConfigModel = [delegate collectionView:self.collectionView layout:self configModelForSectionAtIndex:section];
Implementing the Delegate Protocol
To customize header and footer calculation behavior, implement the JJCollectionViewDelegateRoundFlowLayout protocol defined in JJCollectionViewRoundFlowLayout.h.
Basic Setup
#import "JJCollectionViewRoundFlowLayout.h"
- (void)viewDidLoad {
[super viewDidLoad];
JJCollectionViewRoundFlowLayout *layout = [JJCollectionViewRoundFlowLayout new];
layout.isRoundEnabled = YES;
layout.isCalculateHeader = YES;
layout.isCalculateFooter = YES;
layout.delegate = self;
self.collectionView.collectionViewLayout = layout;
}
Controlling Header and Footer Backgrounds
Override default calculation flags for specific sections:
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
isCalculateHeaderViewIndex:(NSInteger)section {
// Only even-indexed sections calculate header backgrounds
return (section % 2 == 0);
}
- (BOOL)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
isCalculateFooterViewIndex:(NSInteger)section {
return YES;
}
Providing Visual Configuration
Supply styling and custom border insets:
- (JJCollectionViewRoundConfigModel *)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
configModelForSectionAtIndex:(NSInteger)section {
JJCollectionViewRoundConfigModel *model = [JJCollectionViewRoundConfigModel new];
model.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];
model.cornerRadius = 12.0;
model.borderWidth = 1.0;
model.borderColor = [UIColor lightGrayColor];
model.shadowColor = [UIColor blackColor];
model.shadowOpacity = 0.2;
model.shadowRadius = 4.0;
return model;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
borderEdgeInsertsForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(5, 10, 5, 10);
}
Handling Edge Cases
Empty Sections
When a section contains no items, the layout checks the isCanCalculateWhenRowEmpty property or delegates to collectionView:layout:isCanCalculateWhenRowEmptyWithSection:. If enabled, the layout calculates the background based solely on the header and footer frames, or the section's theoretical bounds if neither supplementary view exists.
Irregular Cell Sizes
For flow layouts with variable cell heights, enabling isCalculateTypeOpenIrregularitiesCell ensures the rounded background encompasses all cells regardless of their vertical position. The layout calls calculateIrregularitiesCellByMinTopFrameWithLayout: and calculateIrregularitiesCellByMaxBottomFrameWithLayout: in JJCollectionViewFlowLayoutUtils to determine the true bounds.
Touch Animations
If isDecorationViewTouchAnimationEnable is set, or if the delegate implements collectionView:layout:isDecorationViewShowAnimationAtIndex:, the decoration view receives a JJCollectionViewTouchAnimationConfigModel. The internal JJCollectionReusableView class handles tap gestures, applying scale transforms to both the background and the cells within that section.
Summary
- Frame Calculation: The layout merges header, footer, and cell frames using
CGRectUnioninJJCollectionViewRoundFlowLayout.mto determine total section bounds. - Delegate Control: Implement
isCalculateHeaderViewIndex:andisCalculateFooterViewIndex:to selectively enable backgrounds per section, overriding the defaultisCalculateHeaderandisCalculateFooterproperties. - Inset Configuration: Use
borderEdgeInsertsForSectionAtIndex:to specify spacing between the rounded background and section content, separate from standardsectionInset. - Edge Case Handling: Empty sections and irregular cell layouts are supported through dedicated delegate methods and calculation utilities in
JJCollectionViewFlowLayoutUtils. - Visual Customization: The
JJCollectionViewRoundConfigModelprovides comprehensive styling options including corner radius, shadows, borders, and background colors rendered byJJCollectionReusableView.
Frequently Asked Questions
How do I disable header background calculation for specific sections?
Implement the collectionView:layout:isCalculateHeaderViewIndex: delegate method. Return NO for sections that should not display a background behind their headers. The layout defaults to the isCalculateHeader property value when the delegate method is not implemented.
What happens if a section has no items but I still want a rounded background?
Set the isCanCalculateWhenRowEmpty property to YES or implement collectionView:layout:isCanCalculateWhenRowEmptyWithSection: and return YES for the specific section. The layout will then calculate the background frame using only the header and footer attributes, or the section's theoretical bounds if neither exists.
How do custom border insets differ from standard section insets?
Border insets are specific to the rounded background decoration and are supplied via collectionView:layout:borderEdgeInsertsForSectionAtIndex:. They control the spacing between the edge of the rounded background and the content. Section insets (sectionInset) control the spacing between cells and the collection view boundaries. The layout applies both in JJCollectionViewRoundFlowLayout.m when calculating the final decoration view frame.
Can I animate the rounded background when the user taps on it?
Yes. Enable isDecorationViewTouchAnimationEnable on the layout, or implement collectionView:layout:isDecorationViewShowAnimationAtIndex: to enable animations for specific sections. The internal JJCollectionReusableView class handles touch events and applies scale animations using JJCollectionViewTouchAnimationConfigModel settings. If you don't provide a custom animation configuration, the layout uses default values from the model class.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →