How to Customize Cell Alignment for Specific Sections Using Delegates in JJCollectionViewRoundFlowLayout
JJCollectionViewRoundFlowLayout supports per-section cell alignment through the JJCollectionViewDelegateRoundFlowLayout protocol, allowing you to override the global collectionCellAlignmentType setting for individual sections by implementing collectionView:layout:alignmentTypeAtSection:.
JJCollectionViewRoundFlowLayout extends UICollectionViewFlowLayout to provide rounded section backgrounds and flexible cell alignment options. When building complex collection views with heterogeneous sections, you often need different horizontal alignments for different sections—some left-aligned, others centered or right-aligned. This library solves that problem through a delegate-based approach that queries alignment preferences on a per-section basis during the layout calculation cycle.
Understanding Global vs. Per-Section Alignment Scope
The library provides two distinct scopes for controlling horizontal cell alignment in vertical-scrolling collection views:
- Global alignment: Set the
collectionCellAlignmentTypeproperty on the layout object. This applies uniformly to all sections unless overridden. - Per-section alignment: Implement the delegate method
collectionView:layout:alignmentTypeAtSection:. The layout queries this method for each section duringlayoutAttributesForElementsInRect:, falling back to the global setting if the delegate does not implement the selector.
By default, the layout uses JJCollectionViewFlowLayoutAlignmentTypeBySystem, which defers to the standard UIKit behavior.
How the Delegate Consultation Works
During the layout calculation in JJCollectionViewRoundFlowLayout.m (lines 556–562), the layout checks whether the delegate responds to the alignment selector:
id delegate = self.collectionView.delegate;
if ([delegate respondsToSelector:@selector(collectionView:layout:alignmentTypeAtSection:)]) {
// Delegate will provide per-section alignment
}
If the method is present, the layout groups attributes by section using groupLayoutAttributesForElementsBySectionWithLayoutAttributesAttrs:, then processes each group through analysisCellSettingFrameWithLayoutAttributesAttrs:toChangeAttributesAttrsList:cellAlignmentType:. The actual frame adjustments for left, center, and right alignment are implemented in the JJCollectionViewRoundFlowLayout+Alignment category methods (evaluatedCellSettingFrameByLeft…, …Center…, …Right…).
Available Alignment Types
The alignment behavior is controlled by the JJCollectionViewRoundFlowLayoutAlignmentType enum defined in JJCollectionViewFlowLayoutConfig.h (lines 11–17):
typedef enum : NSUInteger {
JJCollectionViewFlowLayoutAlignmentTypeBySystem = 0,
JJCollectionViewFlowLayoutAlignmentTypeByLeft,
JJCollectionViewFlowLayoutAlignmentTypeByCenter,
JJCollectionViewFlowLayoutAlignmentTypeByRight,
JJCollectionViewFlowLayoutAlignmentTypeByRightAndStartR,
} JJCollectionViewRoundFlowLayoutAlignmentType;
- BySystem: Uses standard UICollectionViewFlowLayout behavior
- ByLeft: Aligns cells to the left edge of the section
- ByCenter: Centers cells within the section
- ByRight: Aligns cells to the right edge
- ByRightAndStartR: Right alignment with RTL (Right-to-Left) layout support
Implementing Per-Section Alignment
Basic Setup via Collection View Delegate
The simplest approach uses your view controller as the delegate. Ensure your class conforms to JJCollectionViewDelegateRoundFlowLayout and implement the alignment method:
@interface MyViewController () <JJCollectionViewDelegateRoundFlowLayout>
@end
@implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
JJCollectionViewRoundFlowLayout *flow = [[JJCollectionViewRoundFlowLayout alloc] init];
flow.scrollDirection = UICollectionViewScrollDirectionVertical;
UICollectionView *cv = [[UICollectionView alloc] initWithFrame:self.view.bounds
collectionViewLayout:flow];
cv.delegate = self; // Critical: sets the alignment delegate
cv.dataSource = self;
[self.view addSubview:cv];
}
#pragma mark - JJCollectionViewDelegateRoundFlowLayout
- (JJCollectionViewRoundFlowLayoutAlignmentType)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)layout
alignmentTypeAtSection:(NSInteger)section {
// Example: Even sections centered, odd sections left-aligned
return (section % 2 == 0)
? JJCollectionViewFlowLayoutAlignmentTypeByCenter
: JJCollectionViewFlowLayoutAlignmentTypeByLeft;
}
@end
The delegate method declaration resides in JJCollectionViewRoundFlowLayout.h (lines 47–53).
Using a Separate Delegate Object
For better separation of concerns, assign a dedicated delegate to the layout's delegate property:
// AlignmentProvider.h
@interface AlignmentProvider : NSObject <JJCollectionViewDelegateRoundFlowLayout>
@end
// AlignmentProvider.m
@implementation AlignmentProvider
- (JJCollectionViewRoundFlowLayoutAlignmentType)collectionView:(UICollectionView *)c
layout:(UICollectionViewLayout *)l
alignmentTypeAtSection:(NSInteger)s {
return (s == 2) ? JJCollectionViewFlowLayoutAlignmentTypeByRight
: JJCollectionViewFlowLayoutAlignmentTypeByCenter;
}
@end
// Configuration
JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
AlignmentProvider *provider = [AlignmentProvider new];
layout.delegate = provider; // Custom delegate separate from collectionView.delegate
Fallback to Global Settings
If you need uniform alignment without per-section logic, set the global property and omit the delegate method:
JJCollectionViewRoundFlowLayout *layout = [[JJCollectionViewRoundFlowLayout alloc] init];
layout.collectionCellAlignmentType = JJCollectionViewFlowLayoutAlignmentTypeByRight;
// All sections align right; no delegate implementation required
Summary
- JJCollectionViewRoundFlowLayout queries the delegate method
collectionView:layout:alignmentTypeAtSection:for each section during layout calculations inJJCollectionViewRoundFlowLayout.m. - The layout supports five alignment types defined in
JJCollectionViewFlowLayoutConfig.h: System, Left, Center, Right, and RightAndStartR. - You can use the collection view's delegate or assign a separate delegate object via the
delegateproperty. - If the delegate does not implement the alignment method, the layout falls back to the
collectionCellAlignmentTypeproperty value. - Frame calculations are handled by the
JJCollectionViewRoundFlowLayout+Alignmentcategory methods.
Frequently Asked Questions
What happens if I don't implement the delegate method?
If the delegate does not respond to collectionView:layout:alignmentTypeAtSection:, the layout uses the global collectionCellAlignmentType property for that section. If no global type is set, it defaults to JJCollectionViewFlowLayoutAlignmentTypeBySystem.
Can I use a different delegate than the collection view's delegate?
Yes. While the layout automatically checks self.collectionView.delegate first, you can assign a separate object conforming to JJCollectionViewDelegateRoundFlowLayout to the layout's delegate property. This is useful when you want to isolate layout logic from your view controller.
Which alignment type should I use for right-aligned layouts with RTL support?
Use JJCollectionViewFlowLayoutAlignmentTypeByRightAndStartR instead of ByRight. This enum value ensures proper behavior in Right-to-Left language environments by respecting the layout direction, whereas ByRight applies a fixed right alignment regardless of locale.
Where does the actual frame calculation happen?
The frame adjustments occur in JJCollectionViewRoundFlowLayout+Alignment through helper methods like evaluatedCellSettingFrameByLeftWith…, …ByCenter…, and …ByRight…. These are called from analysisCellSettingFrameWithLayoutAttributesAttrs:toChangeAttributesAttrsList:cellAlignmentType: after the delegate provides the alignment type for the section.
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 →