// // KBSvipFlowLayout.m // keyBoard // // SVIP 页面自定义布局,支持多个 Section 背景装饰视图 // #import "KBSvipFlowLayout.h" #import "KBSvipBenefitBgView.h" static NSString * const kKBSvipOuterBgKind = @"KBSvipOuterBgDecoration"; // 外层大背景(18圆角,包裹全部) static NSString * const kKBSvipBenefitBgKind = @"KBSvipBenefitBgDecoration"; // 内层权益背景(15圆角) #pragma mark - 外层大背景视图(18圆角,包裹订阅选项+权益列表) @interface KBSvipOuterBgView : UICollectionReusableView @end @implementation KBSvipOuterBgView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor whiteColor]; self.layer.cornerRadius = 18; self.layer.masksToBounds = YES; } return self; } @end #pragma mark - KBSvipFlowLayout @interface KBSvipFlowLayout () @property (nonatomic, strong) NSMutableArray *decorationAttributes; @end @implementation KBSvipFlowLayout - (instancetype)init { if (self = [super init]) { _decorationSection = 1; // Section 1 是权益列表 [self registerClass:[KBSvipOuterBgView class] forDecorationViewOfKind:kKBSvipOuterBgKind]; [self registerClass:[KBSvipBenefitBgView class] forDecorationViewOfKind:kKBSvipBenefitBgKind]; } return self; } - (void)prepareLayout { [super prepareLayout]; self.decorationAttributes = [NSMutableArray array]; NSInteger numberOfSections = [self.collectionView numberOfSections]; if (numberOfSections < 2) { return; } NSInteger itemCount0 = [self.collectionView numberOfItemsInSection:0]; NSInteger itemCount1 = [self.collectionView numberOfItemsInSection:1]; if (itemCount0 == 0 || itemCount1 == 0) { return; } // 获取 Section 0 第一个 item UICollectionViewLayoutAttributes *firstItemAttr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; // 获取 Section 1 Header UICollectionViewLayoutAttributes *benefitHeaderAttr = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]]; // 获取 Section 1 最后一个 item UICollectionViewLayoutAttributes *lastBenefitAttr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:itemCount1 - 1 inSection:1]]; if (!firstItemAttr || !benefitHeaderAttr || !lastBenefitAttr) { return; } UIEdgeInsets sectionInset0 = [self insetForSection:0]; UIEdgeInsets sectionInset1 = [self insetForSection:1]; // 固定的外层背景边距(不跟随 Section inset) CGFloat outerPadding = 16; // 1. 外层大背景(18圆角):固定距离屏幕左右 16 { CGFloat minY = CGRectGetMinY(firstItemAttr.frame) - sectionInset0.top; CGFloat maxY = CGRectGetMaxY(lastBenefitAttr.frame) + 16; CGFloat x = outerPadding; CGFloat width = self.collectionView.bounds.size.width - outerPadding * 2; CGRect frame = CGRectMake(x, minY, width, maxY - minY); UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:kKBSvipOuterBgKind withIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; attr.frame = frame; attr.zIndex = -2; // 最底层 [self.decorationAttributes addObject:attr]; } // 2. 内层权益背景(15圆角):从 Section 1 Header 到 Section 1 底部,左右距离外层 8px { CGFloat innerPadding = 8; // 距离外层背景的边距 CGFloat minY = CGRectGetMinY(benefitHeaderAttr.frame); CGFloat maxY = CGRectGetMaxY(lastBenefitAttr.frame) + 16; CGFloat x = outerPadding + innerPadding; CGFloat width = self.collectionView.bounds.size.width - (outerPadding + innerPadding) * 2; CGRect frame = CGRectMake(x, minY, width, maxY - minY); UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:kKBSvipBenefitBgKind withIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]]; attr.frame = frame; attr.zIndex = -1; // 在外层背景之上 [self.decorationAttributes addObject:attr]; } } - (UIEdgeInsets)insetForSection:(NSInteger)section { UIEdgeInsets sectionInset = self.sectionInset; if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) { sectionInset = [(id)self.collectionView.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:section]; } return sectionInset; } - (NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { NSMutableArray *attrs = [[super layoutAttributesForElementsInRect:rect] mutableCopy]; for (UICollectionViewLayoutAttributes *decorationAttr in self.decorationAttributes) { if (CGRectIntersectsRect(rect, decorationAttr.frame)) { [attrs addObject:decorationAttr]; } } return attrs; } - (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath { for (UICollectionViewLayoutAttributes *attr in self.decorationAttributes) { if ([attr.representedElementKind isEqualToString:elementKind] && attr.indexPath.section == indexPath.section) { return attr; } } return [super layoutAttributesForDecorationViewOfKind:elementKind atIndexPath:indexPath]; } @end