How to Use JJCollectionViewRoundFlowLayout with IGListCollectionView Delegate: Complete Integration Guide

Use the SQCollectionRoundFlowLayout wrapper class to bridge JJCollectionViewRoundFlowLayout with IGListKit by forwarding delegate calls to your IGListSectionController implementations.

JJCollectionViewRoundFlowLayout provides rounded backgrounds, shadows, and borders for UICollectionView sections, but integrating it with IGListKit requires special handling since the IGListAdapter owns the collection view's delegate. In the kingjiajie/jjcollectionviewroundflowlayout repository, the SQCollectionRoundFlowLayout class solves this by routing JJCollectionViewDelegateRoundFlowLayout protocol methods to the appropriate section controllers.

Architecture Overview

The integration relies on a delegation-forwarding pattern that preserves IGListKit's data-driven architecture while allowing per-section customization of rounded decorations.

Component Role Key Source
JJCollectionViewRoundFlowLayout Core layout class that draws section background decorations, computes insets, shadows, and alignment. JJCollectionViewRoundFlowLayout/Classes/JJCollectionViewRoundFlowLayout.h
JJCollectionViewDelegateRoundFlowLayout Protocol defining per-section customization methods including configuration models and border insets. JJCollectionViewRoundFlowLayout/Classes/JJCollectionViewRoundFlowLayout.h
SQCollectionRoundFlowLayout Subclass that forwards all delegate calls to the IGListAdapter's section controller for each index. Example/JJCollectionViewRoundFlowLayout/SQCollectionRoundFlowLayout.h Example/JJCollectionViewRoundFlowLayout/SQCollectionRoundFlowLayout.m
IGListSectionController Your subclass implements delegate methods to customize the rounded background for its specific section. Referenced in Example/JJCollectionViewRoundFlowLayout/IGListkitViewController.m

Delegation Flow

When the layout needs configuration values, SQCollectionRoundFlowLayout queries the IGListAdapter to locate the section controller owning that section index. If the controller implements the required JJCollectionViewDelegateRoundFlowLayout method, the layout uses that value; otherwise, it returns sensible defaults like UIEdgeInsetsZero.

Step-by-Step Integration Guide

Installing the Dependency

Add the pod to your Podfile and run pod install:

pod 'JJCollectionViewRoundFlowLayout'

Setting Up the Adapter and Layout

Create an IGListAdapter and instantiate SQCollectionRoundFlowLayout with that adapter. The wrapper stores a weak reference to route delegate calls.

// Create the IGListAdapter
self.adapter = [[IGListAdapter alloc] initWithUpdater:IGListAdapterUpdater.new
                                       viewController:self
                                     workingRangeSize:2];

// Initialize the wrapper layout with the adapter
SQCollectionRoundFlowLayout *layout = [[SQCollectionRoundFlowLayout alloc]
                                       initWithIGListAdapter:self.adapter];

// Create the collection view
IGListCollectionView *collectionView = [[IGListCollectionView alloc]
    initWithFrame:self.view.bounds
    collectionViewLayout:layout];

collectionView.translatesAutoresizingMaskIntoConstraints = NO;
collectionView.backgroundColor = UIColor.whiteColor;

// Connect adapter to collection view
self.adapter.collectionView = collectionView;
self.adapter.dataSource = self;

Implementing the Section Controller

Create a subclass of IGListSectionController that adopts JJCollectionViewDelegateRoundFlowLayout. Implement the optional methods to customize the rounded background, shadows, and alignment for that specific section.

@interface MyIGListSectionController : IGListSectionController
                                        <IGListSectionType,
                                         JJCollectionViewDelegateRoundFlowLayout>
@end

@implementation MyIGListSectionController

- (NSInteger)numberOfItems {
    return 5;
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                        layout:(UICollectionViewLayout *)layout
    borderEdgeInsertsForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(8.f, 10.f, 8.f, 10.f);
}

- (JJCollectionViewRoundConfigModel *)collectionView:(UICollectionView *)collectionView
                                               layout:(UICollectionViewLayout *)layout
                    configModelForSectionAtIndex:(NSInteger)section {
    JJCollectionViewRoundConfigModel *model = [[JJCollectionViewRoundConfigModel alloc] init];
    model.cornerRadius = (section == 2) ? 0.f : 10.f;
    model.backgroundColor = UIColor.whiteColor;
    model.shadowColor = [UIColor colorWithRed:204/255.0 green:204/255.0 blue:204/255.0 alpha:0.6];
    model.shadowOffset = CGSizeZero;
    model.shadowOpacity = 1.f;
    model.shadowRadius = 4.f;
    return model;
}

- (JJCollectionViewRoundFlowLayoutAlignmentType)collectionView:(UICollectionView *)collectionView
                                                         layout:(UICollectionViewLayout *)layout
                                         alignmentTypeAtSection:(NSInteger)section {
    return JJCollectionViewRoundFlowLayoutAlignmentTypeLeft;
}

- (UICollectionViewCell *)cellForItemAtIndex:(NSInteger)index {
    UICollectionViewCell *cell = [self.collectionContext 
        dequeueReusableCellOfClass:UICollectionViewCell.class
                forSectionController:self
                           atIndex:index];
    cell.backgroundColor = (index % 2 == 0) ? UIColor.redColor : UIColor.orangeColor;
    return cell;
}

@end

Return this section controller from your IGListAdapterDataSource implementation:

- (IGListSectionController<IGListSectionType> *)listAdapter:(IGListAdapter *)listAdapter
                               sectionControllerForObject:(id)object {
    MyIGListSectionController *controller = [[MyIGListSectionController alloc] init];
    controller.inset = UIEdgeInsetsMake(40.f, 20.f, 40.f, 20.f);
    controller.minimumLineSpacing = 10.f;
    controller.minimumInteritemSpacing = 5.f;
    return controller;
}

Complete Implementation Example

The following view controller demonstrates the full wiring between IGListKit and the rounded layout, including adapter setup, layout initialization, and data source methods.

// IGListkitViewController.m
#import "IGListkitViewController.h"
#import <IGListKit/IGListKit.h>
@import JJCollectionViewRoundFlowLayout;
#import "SQCollectionRoundFlowLayout.h"
#import "MyIGListSectionController.h"

@interface IGListkitViewController () <IGListAdapterDataSource, IGListAdapterDelegate>
@property (strong, nonatomic) IGListCollectionView *collectionView;
@property (nonatomic, strong) IGListAdapter *adapter;
@end

@implementation IGListkitViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupAdapterAndLayout];
    [self layoutCollectionView];
}

- (void)setupAdapterAndLayout {
    self.adapter = [[IGListAdapter alloc] initWithUpdater:IGListAdapterUpdater.new
                                           viewController:self
                                         workingRangeSize:2];
    
    SQCollectionRoundFlowLayout *layout = [[SQCollectionRoundFlowLayout alloc] 
                                          initWithIGListAdapter:self.adapter];
    
    self.collectionView = [[IGListCollectionView alloc] 
        initWithFrame:self.view.bounds
        collectionViewLayout:layout];
    self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
    self.collectionView.backgroundColor = UIColor.whiteColor;
    
    self.adapter.collectionView = self.collectionView;
    self.adapter.dataSource = self;
    self.adapter.delegate = self;
    [self.view addSubview:self.collectionView];
}

- (void)layoutCollectionView {
    UIView *cv = self.collectionView;
    UIView *parent = self.view;
    [parent addConstraints:@[
        [NSLayoutConstraint constraintWithItem:cv attribute:NSLayoutAttributeTop
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:parent attribute:NSLayoutAttributeTop multiplier:1 constant:0],
        [NSLayoutConstraint constraintWithItem:cv attribute:NSLayoutAttributeLeft
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:parent attribute:NSLayoutAttributeLeft multiplier:1 constant:0],
        [NSLayoutConstraint constraintWithItem:cv attribute:NSLayoutAttributeBottom
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:parent attribute:NSLayoutAttributeBottom multiplier:1 constant:0],
        [NSLayoutConstraint constraintWithItem:cv attribute:NSLayoutAttributeRight
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:parent attribute:NSLayoutAttributeRight multiplier:1 constant:0],
    ]];
}

#pragma mark - IGListAdapterDataSource

- (NSArray<id<IGListDiffable>> *)objectsForListAdapter:(IGListAdapter *)listAdapter {
    return @[@"1", @"2", @"3", @"4", @"5", @"6", @"7"];
}

- (IGListSectionController<IGListSectionType> *)listAdapter:(IGListAdapter *)listAdapter
                               sectionControllerForObject:(id)object {
    MyIGListSectionController *controller = [[MyIGListSectionController alloc] init];
    controller.inset = UIEdgeInsetsMake(40.f, 20.f, 40.f, 20.f);
    controller.minimumLineSpacing = 10.f;
    controller.minimumInteritemSpacing = 5.f;
    return controller;
}

- (UIView *)emptyViewForListAdapter:(IGListAdapter *)listAdapter {
    return nil;
}

@end

Key Source Files and Responsibilities

Understanding these specific files in the kingjiajie/jjcollectionviewroundflowlayout repository helps you customize the integration:

  • JJCollectionViewRoundFlowLayout/Classes/JJCollectionViewRoundFlowLayout.h — Defines the core JJCollectionViewRoundFlowLayout class and the JJCollectionViewDelegateRoundFlowLayout protocol with methods like configModelForSectionAtIndex: and borderEdgeInsertsForSectionAtIndex:.

  • JJCollectionViewRoundFlowLayout/Classes/JJCollectionViewRoundConfigModel.h — Contains the model class holding visual properties: cornerRadius, backgroundColor, shadowColor, shadowOpacity, shadowRadius, and border settings.

  • Example/JJCollectionViewRoundFlowLayout/SQCollectionRoundFlowLayout.m — Implements the forwarding logic in methods like collectionView:layout:configModelForSectionAtIndex: by querying the adapter via [_adapter sectionControllerForObject:[_adapter objectAtSection:section]] and forwarding to the controller if it responds to the selector.

  • Example/JJCollectionViewRoundFlowLayout/IGListkitViewController.m — Reference implementation showing how to wire the adapter, layout, and data source together in a production view controller.

Summary

  • Use SQCollectionRoundFlowLayout as a drop-in replacement for JJCollectionViewRoundFlowLayout when working with IGListKit; it handles all delegate forwarding automatically.

  • Initialize with the adapter by calling initWithIGListAdapter: to establish the forwarding chain.

  • Implement JJCollectionViewDelegateRoundFlowLayout in your IGListSectionController subclasses to control corner radius, background color, shadows, and border insets per section.

  • Return configuration models via configModelForSectionAtIndex: to customize the visual appearance without breaking IGListKit's data-driven architecture.

  • Reference the example files in the repository's Example/ directory for complete working implementations of the wrapper and view controller setup.

Frequently Asked Questions

How does SQCollectionRoundFlowLayout handle delegate methods without a traditional collection view delegate?

SQCollectionRoundFlowLayout overrides the delegate getter to return self, then implements each JJCollectionViewDelegateRoundFlowLayout method by querying the IGListAdapter for the section controller at the specified index. According to the source in SQCollectionRoundFlowLayout.m, it calls [_adapter sectionControllerForObject:[_adapter objectAtSection:section]] and checks if the returned controller responds to the delegate method using respondsToSelector: before forwarding the call.

Can I use different corner radii for different sections in the same collection view?

Yes. Because the layout queries the section controller for each index via configModelForSectionAtIndex:, you can return different JJCollectionViewRoundConfigModel instances with varying cornerRadius values. In your IGListSectionController implementation, inspect the section parameter or instance variables to determine the appropriate radius, as shown in the example where model.cornerRadius is set conditionally based on the section index.

What happens if my section controller does not implement a specific delegate method?

The wrapper provides safe defaults. In SQCollectionRoundFlowLayout.m, methods like borderEdgeInsertsForSectionAtIndex: return UIEdgeInsetsZero and alignmentTypeAtSection: returns the default alignment if the section controller does not implement the protocol method. This ensures the layout functions correctly even with partial protocol adoption.

Do I need to set the collection view's delegate property manually when using this integration?

No. You should not set collectionView.delegate manually because IGListAdapter manages the delegate and data source. The SQCollectionRoundFlowLayout acts as its own delegate internally and forwards specific rounded-layout queries to your section controllers, allowing the adapter to maintain control over the standard collection view delegate pattern.

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 →