# Implementing Section Borders with JJCollectionViewRoundFlowLayout

> Learn how to implement section borders in your UICollectionView using JJCollectionViewRoundFlowLayout. Configure borders easily via delegate methods for polished section designs.

- Repository: [Kingjiajie_Go/jjcollectionviewroundflowlayout](https://github.com/kingjiajie/jjcollectionviewroundflowlayout)
- Tags: how-to-guide
- Published: 2026-03-05

---

**You configure section borders by returning a `JJCollectionViewRoundConfigModel` with `borderWidth` and `borderColor` values from the delegate method `collectionView:layout:configModelForSectionAtIndex:`, which the layout applies as native `CALayer` borders on the section's decoration view.**

The **JJCollectionViewRoundFlowLayout** library (available at `kingjiajie/jjcollectionviewroundflowlayout`) extends `UICollectionViewFlowLayout` to draw rounded backgrounds with optional borders around entire sections. Unlike subclassing cells, this approach uses decoration views—separate from the cell hierarchy—to render visual containers, ensuring borders appear behind content and respond to layout changes automatically.

## How the Border System Works

Borders in **JJCollectionViewRoundFlowLayout** are rendered as native `CALayer` properties on decoration views that sit behind each collection view section. The layout does not hardcode border values; instead, it queries your delegate for a configuration model per section.

The configuration model (`JJCollectionViewRoundConfigModel`) defines border appearance through two key properties defined in [`JJCollectionViewRoundConfigModel.h`](https://github.com/kingjiajie/jjcollectionviewroundflowlayout/blob/main/JJCollectionViewRoundConfigModel.h) (lines 14‑19):

- **`borderWidth`**: The width of the border line in points (`CGFloat`)
- **`borderColor`**: The color of the border (`UIColor`)

When `borderWidth` is greater than zero, the layout creates a decoration view attribute that stores these values. The actual rendering occurs in `JJCollectionReusableView` (the decoration view class), which applies the values to its backing layer during `applyLayoutAttributes:`.

## Configuring Borders via the Delegate Protocol

To enable borders, your view controller must conform to **`JJCollectionViewDelegateRoundFlowLayout`** and implement the required configuration method. The layout calls this method during `prepareLayout` to retrieve section-specific settings.

The delegate method signature is:

```objc
- (JJCollectionViewRoundConfigModel *)collectionView:(UICollectionView *)collectionView
                                              layout:(JJCollectionViewLayout *)collectionViewLayout
                       configModelForSectionAtIndex:(NSInteger)section;

```

Inside `JJCollectionViewRoundFlowLayout.m` (lines 495‑497), the layout checks for this implementation:

```objc
if ([delegate respondsToSelector:@selector(collectionView:layout:configModelForSectionAtIndex:)]) {
    attr.myConfigModel = [delegate collectionView:self.collectionView
                                            layout:self
                    configModelForSectionAtIndex:section];
}

```

If you return a model with default values (zero width), no border appears. To render a visible border, explicitly set the width and color properties:

```objc
#pragma mark - JJCollectionViewDelegateRoundFlowLayout

- (JJCollectionViewRoundConfigModel *)collectionView:(UICollectionView *)collectionView
                                              layout:(JJCollectionViewLayout *)layout
                       configModelForSectionAtIndex:(NSInteger)section {
    JJCollectionViewRoundConfigModel *model = [[JJCollectionViewRoundConfigModel alloc] init];
    
    // Background configuration
    model.backgroundColor = [UIColor systemBackgroundColor];
    model.cornerRadius = 12.0;
    
    // Border configuration
    model.borderWidth = 1.5;
    model.borderColor = [UIColor separatorColor];
    
    return model;
}

```

## How Borders Are Rendered on Screen

The border is not drawn via Core Graphics in `drawRect:`; instead, it uses the hardware-accelerated `CALayer` border properties for optimal scrolling performance.

When the layout finishes calculations in `prepareLayout`, it creates `JJCollectionViewRoundLayoutAttributes` containing the `myConfigModel`. During `layoutAttributesForElementsInRect:`, these attributes are returned to the collection view, which instantiates or updates the corresponding `JJCollectionReusableView` decoration views.

In `JJCollectionViewRoundFlowLayout.m` (lines 106‑114), the layout attributes are applied to the view's layer:

```objc
// Inside JJCollectionReusableView (decoration view) implementation
view.layer.borderWidth = model.borderWidth;

if (@available(iOS 13.0, *)) {
    // Respect dark mode and trait collections automatically
    view.layer.borderColor = [model.borderColor resolvedColorWithTraitCollection:self.traitCollection].CGColor;
} else {
    view.layer.borderColor = model.borderColor.CGColor;
}

```

This implementation ensures that:
- **Dynamic colors** (like `UIColor.separatorColor`) automatically adapt to Light/Dark mode on iOS 13+
- **Performance** remains high because the system composites the border in the render server, not the CPU
- **Animation** works seamlessly with collection view updates

## Customizing Border Position with Edge Insets

By default, the border aligns with the section's edge insets calculated from the flow layout's `sectionInset`. To create a border that is inset relative to the background (or extends beyond it), implement the optional delegate method `collectionView:layout:borderEdgeInsertsForSectionAtIndex:`.

This method returns `UIEdgeInsets` that shrink or expand the decoration view's frame independently of the content inset:

```objc
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                        layout:(JJCollectionViewLayout *)layout
borderEdgeInsertsForSectionAtIndex:(NSInteger)section {
    // Inset the border 8pt inside the section background
    return UIEdgeInsetsMake(8, 8, 8, 8);
}

```

Behind the scenes, `JJCollectionViewRoundFlowLayout.m` stores this value in the layout attributes (lines 390‑398) and applies it when calculating the final decoration view frame (lines 800‑808):

```objc
// Store the custom inset in the attribute
attr.borderEdgeInsets = userCustomSectionInset;

// Apply inset to the decoration view frame
sectionFrame.origin.x += userCustomSectionInset.left;
sectionFrame.origin.y += userCustomSectionInset.top;
sectionFrame.size.width -= (userCustomSectionInset.left + userCustomSectionInset.right);
sectionFrame.size.height -= (userCustomSectionInset.top + userCustomSectionInset.bottom);

```

Positive values shrink the border toward the center; negative values extend it outward beyond the background bounds.

## Complete Implementation Example

Here is a complete view controller implementation that configures a collection view with rounded sections, background colors, and 1-point separators between sections:

```objc
#import "JJCollectionViewRoundFlowLayout.h"

@interface ViewController () <UICollectionViewDataSource, JJCollectionViewDelegateRoundFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
    layout.delegate = self; // Required for border configuration
    
    self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds
                                           collectionViewLayout:layout];
    self.collectionView.dataSource = self;
    [self.view addSubview:self.collectionView];
}

#pragma mark - JJCollectionViewDelegateRoundFlowLayout

- (JJCollectionViewRoundConfigModel *)collectionView:(UICollectionView *)collectionView
                                              layout:(UICollectionViewLayout *)layout
                       configModelForSectionAtIndex:(NSInteger)section {
    JJCollectionViewRoundConfigModel *model = [[JJCollectionViewRoundConfigModel alloc] init];
    
    // Visual styling
    model.backgroundColor = [UIColor secondarySystemBackgroundColor];
    model.cornerRadius = 8.0;
    
    // Border styling
    model.borderWidth = 1.0;
    model.borderColor = [UIColor systemGray3Color];
    
    return model;
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                        layout:(UICollectionViewLayout *)layout
borderEdgeInsertsForSectionAtIndex:(NSInteger)section {
    // Keep border 4pt inside the background edge
    return UIEdgeInsetsMake(4, 4, 4, 4);
}

#pragma mark - UICollectionViewDataSource

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 3;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 10;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell"
                                                                           forIndexPath:indexPath];
    cell.contentView.backgroundColor = [UIColor systemOrangeColor];
    return cell;
}

@end

```

## Summary

- **Delegate Protocol**: Conform to `JJCollectionViewDelegateRoundFlowLayout` and implement `collectionView:layout:configModelForSectionAtIndex:` to return configuration models.
- **Border Properties**: Set `borderWidth` and `borderColor` on the `JJCollectionViewRoundConfigModel` instance to enable native `CALayer` borders.
- **iOS Version Support**: The implementation automatically uses `resolvedColorWithTraitCollection:` on iOS 13+ to support dynamic colors, falling back to standard `CGColor` on earlier versions.
- **Positioning Control**: Use `collectionView:layout:borderEdgeInsertsForSectionAtIndex:` to inset or outset the border relative to the section background, as calculated in `JJCollectionViewRoundFlowLayout.m` (lines 800‑808).
- **Performance**: Borders render using hardware-accelerated layer properties, not CPU-bound drawing, maintaining smooth scrolling performance.

## Frequently Asked Questions

### How do I remove the border from a specific section while keeping it on others?

Return a `JJCollectionViewRoundConfigModel` with **`borderWidth`** set to `0.0` (or leave it at the default zero) for sections that should not display a border. The layout checks `model.borderWidth` before applying layer properties, so zero width effectively disables the border for that section while preserving the rounded background.

### Does the border color automatically support Dark Mode?

Yes. The implementation in `JJCollectionViewRoundFlowLayout.m` uses **`resolvedColorWithTraitCollection:`** when running on iOS 13 or later, which resolves dynamic colors (like `UIColor.separatorColor` or `UIColor.systemGrayColor`) against the current trait collection before converting to `CGColor`. On iOS 12 and earlier, it falls back to the standard `CGColor` conversion, so static colors work as expected.

### Why are my borders appearing clipped or outside the visible bounds?

This typically occurs when the **`borderEdgeInsets`** are negative (extending outward) but the collection view's bounds or `contentInset` do not provide sufficient space. Ensure your collection view has `clipsToBounds` disabled if you intend borders to extend visibly beyond cell boundaries, or verify that your `borderEdgeInsertsForSectionAtIndex:` implementation returns positive insets if you want the border contained within the section background.

### Can I animate the border color or width when the collection view updates?

Yes. Because the border is rendered via standard `CALayer` properties, you can animate changes by calling `reloadSections:` or invalidating the layout with animation. For custom transitions, modify the model values and trigger `invalidateLayout`—the decoration view will pick up the new `borderWidth` and `borderColor` values and animate if wrapped in a `UIView` animation block, though precise control requires accessing the decoration view directly via the layout's supplementary view APIs.