如何在UICollectionView中直接为section设置圆角与阴影,无需操作cell
实现section层级圆角阴影的最优方案:使用UICollectionView装饰视图

存在不需要修改cell的原生实现方案,核心依赖UICollectionView布局体系中的**装饰视图(Decoration View)**能力,无需处理每个cell的圆角逻辑,所有section背景效果都在cell外部完成。
装饰视图是UICollectionView专门提供的、和section绑定、不属于任何cell/Header/Footer的独立视图层级,默认渲染在所有cell下方,非常适合用来实现section整体的背景、圆角、阴影效果。
方案1:iOS 13+ 极简实现(基于UICollectionViewCompositionalLayout)
该系统版本下CompositionalLayout原生支持给section绑定背景装饰视图,只需要几行代码即可实现:
- 第一步:自定义继承自
UICollectionReusableView的装饰背景类,在内部实现圆角、阴影效果
// Objective-C 示例 @interface SectionBackgroundView : UICollectionReusableView @end @implementation SectionBackgroundView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor whiteColor]; self.layer.cornerRadius = 12; self.layer.shadowColor = [UIColor grayColor].CGColor; self.layer.shadowOffset = CGSizeMake(0, 2); self.layer.shadowOpacity = 0.1; self.layer.shadowRadius = 8; // 不要开启裁剪,否则阴影会被切掉 self.layer.masksToBounds = NO; } return self; } @end
- 第二步:创建布局时注册装饰类,给section绑定背景
// Swift 示例 let layout = UICollectionViewCompositionalLayout { sectionIndex, layoutEnvironment in // 定义item、group的布局逻辑,和普通布局写法完全一致 let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(44)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(44)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16) section.interGroupSpacing = 0 // 核心:绑定section背景装饰 let backgroundItem = NSCollectionLayoutDecorationItem.background(elementKind: "SectionBackgroundView") // 背景的内边距,调整这个可以控制背景左右露出的边距 backgroundItem.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16) section.decorationItems = [backgroundItem] return section } // 注册装饰视图类到布局 layout.register(SectionBackgroundView.self, forDecorationViewOfKind: "SectionBackgroundView")
方案2:兼容iOS13以下版本(自定义FlowLayout)
如果需要适配更低系统版本,自定义UICollectionViewFlowLayout,手动计算每个section的装饰视图frame即可:
- 第一步:同上自定义
SectionBackgroundView装饰类 - 第二步:自定义FlowLayout,重写布局相关方法:
@implementation CustomFlowLayout - (instancetype)init { if (self = [super init]) { // 提前注册装饰类 [self registerClass:SectionBackgroundView.class forDecorationViewOfKind:@"SectionBackgroundView"]; } return self; } - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { NSMutableArray *attrs = [super layoutAttributesForElementsInRect:rect].mutableCopy; NSInteger sectionCount = [self.collectionView numberOfSections]; // 遍历所有section,添加对应装饰视图的布局属性 for (NSInteger i = 0; i < sectionCount; i++) { NSInteger itemCount = [self.collectionView numberOfItemsInSection:i]; if (itemCount == 0) continue; NSIndexPath *firstIndexPath = [NSIndexPath indexPathForItem:0 inSection:i]; NSIndexPath *lastIndexPath = [NSIndexPath indexPathForItem:itemCount-1 inSection:i]; // 获取首尾cell的frame,合并得到整个section的内容frame UICollectionViewLayoutAttributes *firstAttr = [self layoutAttributesForItemAtIndexPath:firstIndexPath]; UICollectionViewLayoutAttributes *lastAttr = [self layoutAttributesForItemAtIndexPath:lastIndexPath]; CGRect sectionFrame = CGRectUnion(firstAttr.frame, lastAttr.frame); // 调整背景frame:比如加宽左右边距,有Header/Footer时也要对应调整高度范围 sectionFrame.origin.x -= 16; sectionFrame.size.width += 32; // 生成装饰视图布局属性,zIndex设为-1保证渲染在cell下方 UICollectionViewLayoutAttributes *decorationAttr = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"SectionBackgroundView" withIndexPath:[NSIndexPath indexPathForItem:0 inSection:i]]; decorationAttr.frame = sectionFrame; decorationAttr.zIndex = -1; [attrs addObject:decorationAttr]; } return attrs; } @end
内容的提问来源于stack exchange,提问作者avregi
相关产品推荐
相关产品推荐

