Supporting Vertical and Horizontal Scrolling with Rounded Section Layouts in iOS
JJCollectionViewRoundFlowLayout automatically adapts its rounded background decoration to both vertical and horizontal scrolling by calculating section frames relative to the current scrollDirection property.
JJCollectionViewRoundFlowLayout is a drop-in replacement for UICollectionViewFlowLayout that draws rounded section backgrounds using decoration views. The layout engine detects whether the collection view scrolls vertically or horizontally and adjusts all size and position calculations accordingly, making it straightforward to implement rounded section layouts in any orientation.
How Scroll Direction Affects Section Frame Calculations
The layout determines the scrolling axis by reading self.scrollDirection inherited from UICollectionViewFlowLayout. In prepareLayout, the code builds sectionFrame using a conditional that expands the background either across the width (vertical scrolling) or height (horizontal scrolling):
sectionFrame = self.scrollDirection == UICollectionViewScrollDirectionVertical ?
CGRectMake(rect.origin.x, rect.origin.y, self.collectionView.bounds.size.width, rect.size.height) :
CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, self.collectionView.bounds.size.height);
This logic appears in JJCollectionViewRoundFlowLayout.m (lines 34-36) and ensures the rounded background always stretches across the full scrollable axis. The same conditional pattern appears in calculateDefaultFrameWithSectionFrame:sectionInset: (lines 29-45) to handle fallback frames when sections lack headers or footers.
Core Architecture and Key Components
JJCollectionViewRoundFlowLayout
The main layout subclass drives the layout pass, creates decoration-view attributes, and adjusts frames for headers, footers, and insets. The implementation in JJCollectionViewRoundFlowLayout.m (lines 79-84, 99-110) handles the core geometry calculations.
JJCollectionViewRoundLayoutAttributes
Custom layout attributes carry the background configuration model, border insets, and optional touch-animation settings. Defined in JJCollectionViewRoundFlowLayout.m (lines 15-22), these attributes pass styling data to the decoration view during the layout pass.
JJCollectionReusableView
The decoration view renders the rounded background, shadow, border, and optional background image. It updates its layer when trait collections change to support dark mode. The rendering logic lives in toChangeCollectionReusableViewRoundInfoWithLayoutAttributes: (lines 85-140 of JJCollectionViewRoundFlowLayout.m).
Delegate Protocol (JJCollectionViewDelegateRoundFlowLayout)
The protocol allows view controllers to supply per-section configuration models, custom border insets, and control header/footer inclusion. Defined in JJCollectionViewRoundFlowLayout.h (lines 16-66), key methods include:
configModelForSectionAtIndex:– ReturnsJJCollectionViewRoundConfigModelwith colors, radius, and shadows.borderEdgeInsertsForSectionAtIndex:– ReturnsUIEdgeInsetsfor the background border, independent ofsectionInset.animationConfigModelForSection:– Optional touch-animation configuration.
Implementing Vertical Scrolling with Rounded Backgrounds
Vertical scrolling is the default behavior. Initialize the layout and assign it to your collection view:
JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds
collectionViewLayout:layout];
collectionView.delegate = self;
collectionView.dataSource = self;
[self.view addSubview:collectionView];
The layout automatically calculates sectionFrame using the full width of the collection view bounds, as shown in the conditional logic in prepareLayout (lines 34-36). For a complete working example, see SecondViewController.m in the repository's Example target (lines 30-34 for layout setup, lines 39-68 for delegate implementation).
Implementing Horizontal Scrolling with Rounded Backgrounds
To switch to horizontal scrolling, set the scrollDirection property before initializing the collection view:
JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; // Key configuration
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds
collectionViewLayout:layout];
When scrollDirection is set to horizontal, the layout adjusts sectionFrame to use the full height of the collection view bounds while allowing the width to expand based on cell content (see the ternary operator in prepareLayout). The repository's ThirdViewController.m demonstrates this configuration.
Customizing Section Appearance
Background Colors, Shadows, and Corner Radius
Implement the delegate method configModelForSectionAtIndex: to return a JJCollectionViewRoundConfigModel instance:
- (JJCollectionViewRoundConfigModel *)collectionView:(UICollectionView *)cv
layout:(UICollectionViewLayout *)layout
configModelForSectionAtIndex:(NSInteger)section {
JJCollectionViewRoundConfigModel *model = [[JJCollectionViewRoundConfigModel alloc] init];
model.backgroundColor = [UIColor systemBackgroundColor];
model.cornerRadius = 12.0;
model.shadowColor = [UIColor blackColor];
model.shadowOpacity = 0.15;
model.shadowRadius = 6.0;
model.shadowOffset = CGSizeMake(0, 2);
return model;
}
Border Insets Independent of Section Insets
To add padding between the rounded background and the section edges without affecting cell positioning, implement borderEdgeInsertsForSectionAtIndex::
- (UIEdgeInsets)collectionView:(UICollectionView *)cv
layout:(UICollectionViewLayout *)layout
borderEdgeInsertsForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(8, 16, 8, 16);
}
These insets are applied to the decoration view frame after the main sectionFrame calculation (see lines 80-84 of layoutAttributesForElementsInRect: in JJCollectionViewRoundFlowLayout.m).
Optional Touch Animations
Enable tap feedback on the rounded background:
layout.isDecorationViewTouchAnimationEnable = YES;
Configure per-section animation behavior:
- (JJCollectionViewTouchAnimationConfigModel *)collectionView:(UICollectionView *)cv
layout:(UICollectionViewLayout *)layout
animationConfigModelForSection:(NSInteger)section {
JJCollectionViewTouchAnimationConfigModel *anim = [JJCollectionViewTouchAnimationConfigModel createDefaultModel];
anim.scale = 0.95;
anim.duration = 0.2;
return anim;
}
Touch handling is implemented in JJCollectionReusableView via touchesBegan: and touchesEnded: methods.
Summary
JJCollectionViewRoundFlowLayoutis a drop-in replacement forUICollectionViewFlowLayoutthat adds rounded background decoration views to collection view sections.- The layout automatically supports both vertical and horizontal scrolling by checking
self.scrollDirectionand adjustingsectionFramecalculations to stretch across the appropriate axis. - All styling (colors, shadows, corner radius) is configured via the
JJCollectionViewDelegateRoundFlowLayoutprotocol usingJJCollectionViewRoundConfigModel. - Border insets can be specified independently of the collection view's
sectionInsetthroughborderEdgeInsertsForSectionAtIndex:. - Optional touch animations are available by setting
isDecorationViewTouchAnimationEnableand implementinganimationConfigModelForSection:.
Frequently Asked Questions
Does JJCollectionViewRoundFlowLayout support both vertical and horizontal layouts simultaneously?
No, the layout respects the single scrollDirection property inherited from UICollectionViewFlowLayout. You must set layout.scrollDirection to either UICollectionViewScrollDirectionVertical or UICollectionViewScrollDirectionHorizontal. The layout calculations in prepareLayout (lines 34-36 of JJCollectionViewRoundFlowLayout.m) use a ternary operator to adjust the sectionFrame based on this property, ensuring the rounded background stretches across the correct axis.
How do I change the corner radius for specific sections only?
Implement the delegate method configModelForSectionAtIndex: and return a JJCollectionViewRoundConfigModel with the desired cornerRadius value for that section. For example, return a model with cornerRadius = 12.0 for section 0 and cornerRadius = 20.0 for section 1. The layout attributes will carry this configuration to the JJCollectionReusableView decoration view, which applies the corner radius to its layer in toChangeCollectionReusableViewRoundInfoWithLayoutAttributes:.
Can I use this layout with self-sizing cells?
Yes, JJCollectionViewRoundFlowLayout inherits from UICollectionViewFlowLayout and respects the estimatedItemSize property for self-sizing cells. The layout calculates the sectionFrame based on the actual frames of the first and last cells in each section (see prepareLayout lines 79-110), so it automatically adapts to dynamic cell sizes. Ensure your delegate methods return appropriate config models regardless of cell size changes.
Where is the decoration view rendering implemented?
The rounded background decoration view is implemented in the JJCollectionReusableView class found within JJCollectionViewRoundFlowLayout.m (lines 85-140). This class overrides applyLayoutAttributes: to receive the JJCollectionViewRoundLayoutAttributes containing the configuration model. The method toChangeCollectionReusableViewRoundInfoWithLayoutAttributes: handles the actual Core Layer rendering of the background color, corner radius, shadow, border, and optional background image. The view also responds to trait collection changes to support dark mode updates.
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 →