How JJCollectionViewRoundFlowLayout Handles Empty Cells: Delegate and Property Configuration

JJCollectionViewRoundFlowLayout skips round background decoration for empty sections by default, but provides granular control through the delegate method collectionView:layout:isCanCalculateWhenRowEmptyWithSection: or the Boolean property isCanCalculateWhenRowEmpty.

JJCollectionViewRoundFlowLayout is an open-source iOS library that adds rounded background decoration to UICollectionView sections. When sections contain no cells, the layout must decide whether to render the background decoration anyway. According to the kingjiajie/jjcollectionviewroundflowlayout repository, the library implements a two-tiered decision system in prepareLayout that checks a delegate method first, then falls back to a configuration property.

The Two-Step Empty Section Detection Mechanism

The layout determines whether to draw a round background for a section containing zero items through a prioritized two-step mechanism. This design allows developers to override behavior globally via properties or dynamically via delegate callbacks.

Step 1: Delegate Method Control

If the layout’s delegate implements the optional protocol method, the layout delegates the decision entirely to this method:

- (BOOL)collectionView:(UICollectionView *)collectionView
                layout:(UICollectionViewLayout *)collectionViewLayout
isCanCalculateWhenRowEmptyWithSection:(NSInteger)section;

When the delegate returns NO, the section is skipped and no decoration view is created. Returning YES forces the layout to treat the empty section like a normal one, computing a background view based on any existing header or footer.

Step 2: Property Fallback

If the delegate does not implement the method, the layout falls back to the Boolean property isCanCalculateWhenRowEmpty. When this property is NO (the default), empty sections are skipped. Setting the property to YES forces background calculation for all empty sections globally.

Implementation Details in prepareLayout

The relevant logic lives in prepareLayout within JJCollectionViewRoundFlowLayout.m. The layout iterates through sections and applies the two-step check before creating decoration attributes.

The detection and skipping logic appears around lines 998-1005:

if (numberOfItems > 0) {
    // normal case – obtain first item frame …
} else if ([delegate respondsToSelector:@selector(collectionView:layout:isCanCalculateWhenRowEmptyWithSection:)]) {
    // delegate decides whether to calculate the background for an empty section
    if (![delegate collectionView:self.collectionView
                            layout:self
        isCanCalculateWhenRowEmptyWithSection:section]) {
        continue;   // skip this section
    }
} else if (!self.isCanCalculateWhenRowEmpty) {
    // no delegate, fall back to the property flag
    continue;       // skip this section
}

When the continue statement executes, the layout does not create a JJCollectionViewRoundLayoutAttributes object for that section, preventing any decoration view from entering the collection view hierarchy.

If the section passes the empty-section check, the layout proceeds to compute sectionFrame, optionally merging header and footer frames, applying borderEdgeInsets, and finally appending a decoration attribute:

JJCollectionViewRoundLayoutAttributes *attr =
    [JJCollectionViewRoundLayoutAttributes layoutAttributesForDecorationViewOfKind:JJCollectionViewRoundSection
                                                                     withIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
attr.frame = sectionFrame;
attr.zIndex = -1;
// … configure config model, touch-animation, etc.
[self.decorationViewAttrs addObject:attr];

Configuration Outcomes Matrix

The interaction between the delegate method and the fallback property produces four distinct behaviors:

Delegate Implementation Return Value / Property State Result for Empty Sections
Implements method Returns NO Section is ignored; no background drawn.
Implements method Returns YES Section is processed; background drawn based on header/footer or default frame.
Does not implement isCanCalculateWhenRowEmpty = NO (default) Section is ignored.
Does not implement isCanCalculateWhenRowEmpty = YES Section is processed; background drawn.

Practical Code Examples

Enabling Background for Empty Sections via Property

To globally allow background decoration for all empty sections without implementing delegate methods:

JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
layout.isCanCalculateWhenRowEmpty = YES;   // treat empty sections like normal ones
collectionView.collectionViewLayout = layout;

Controlling Empty Section Handling with Delegate

For dynamic, per-section control, implement the delegate protocol:

@interface MyViewController () <JJCollectionViewDelegateRoundFlowLayout>
@end

@implementation MyViewController

- (BOOL)collectionView:(UICollectionView *)collectionView
               layout:(UICollectionViewLayout *)layout
isCanCalculateWhenRowEmptyWithSection:(NSInteger)section {
    // Only draw backgrounds for even-indexed sections when they are empty
    return (section % 2 == 0);
}

@end

Full Setup with Headers and Footers

When empty sections contain headers or footers, ensure the layout calculates their frames to determine the background bounds:

JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
layout.isCanCalculateWhenRowEmpty = YES;               // allow empty sections
layout.isCalculateHeader = YES;                        // honour header view
layout.isCalculateFooter = YES;                        // honour footer view
layout.delegate = self;                                 // optional delegate for fine-grained control
collectionView.collectionViewLayout = layout;

Summary

  • JJCollectionViewRoundFlowLayout skips decoration for empty sections by default to avoid rendering unnecessary backgrounds.
  • Delegate priority: Implement collectionView:layout:isCanCalculateWhenRowEmptyWithSection: to dynamically control empty section rendering per section.
  • Property fallback: Set isCanCalculateWhenRowEmpty to YES for global enablement when no delegate method exists.
  • Implementation location: The logic resides in prepareLayout inside JJCollectionViewRoundFlowLayout.m, specifically around lines 998-1005.
  • Header/Footer support: When empty sections are processed, the layout still calculates backgrounds based on existing header and footer frames.

Frequently Asked Questions

What happens to the round background when a section has no cells?

By default, no background is drawn. The layout checks if the section contains zero items and skips creating the decoration view unless explicitly permitted via the delegate method collectionView:layout:isCanCalculateWhenRowEmptyWithSection: or the isCanCalculateWhenRowEmpty property set to YES.

Yes. When isCanCalculateWhenRowEmpty is enabled or the delegate permits the section, the layout calculates the sectionFrame by incorporating header and footer frames (if isCalculateHeader and isCalculateFooter are enabled). This ensures the round background surrounds the header or footer even when no cells exist.

Where is the empty section detection logic implemented?

The detection logic is implemented in the prepareLayout method of JJCollectionViewRoundFlowLayout.m, specifically around lines 998-1005. This code block checks numberOfItems, queries the delegate if implemented, or falls back to the isCanCalculateWhenRowEmpty property before deciding whether to continue (skip) or proceed with decoration attribute creation.

Should I use the delegate method or the property for controlling empty sections?

Use the delegate method collectionView:layout:isCanCalculateWhenRowEmptyWithSection: when you need per-section control (for example, only showing backgrounds for specific empty sections). Use the property isCanCalculateWhenRowEmpty when you want a global setting that applies to all empty sections uniformly without implementing delegate methods.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →