//
// OCFTUICollectionViewLeftAlignedFlowLayout.m
// ZNSLSDK
//
// Created by on 2022/4/12.
// Copyright © 2022 yull. All rights reserved.
//
#import "OCFTUICollectionViewLeftAlignedFlowLayout.h"
#define OCFTItemWidth 115.f
#define kDecorationReuseIndentifier @"kUICollectionSectionColorIndentifier"
@interface UICollectionViewLayoutAttributes (OCFTLeftAligned)
-
(void)ocftLeftAlignFrameWithSectionInset:(UIEdgeInsets)sectionInset;
@end
@implementation UICollectionViewLayoutAttributes (OCFTLeftAligned)
- (void)ocftLeftAlignFrameWithSectionInset:(UIEdgeInsets)sectionInset
{
CGRect frame = self.frame;
frame.origin.x = sectionInset.left;
self.frame = frame;
}
@end
@interface UICollectionSectionColorLayoutAttributes : UICollectionViewLayoutAttributes
@property (nonatomic, assign) NSInteger tagg;
@property(nonatomic, strong) UIColor *sectionBgColor;
@property (nonatomic, assign) CGFloat sectionCornerRadius;
@property(nonatomic, strong) UIColor *shadowColor;
@property (nonatomic, assign) CGFloat shadowRadius;
@end
@implementation UICollectionSectionColorLayoutAttributes
@end
@implementation UICollectionSectionColorReusableView
- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
[super applyLayoutAttributes:layoutAttributes];
if ([layoutAttributes isKindOfClass:[UICollectionSectionColorLayoutAttributes class]]) {
self.tag = [(UICollectionSectionColorLayoutAttributes *)layoutAttributes tagg];
self.backgroundColor = [(UICollectionSectionColorLayoutAttributes *)layoutAttributes sectionBgColor];
self.layer.cornerRadius = [(UICollectionSectionColorLayoutAttributes *)layoutAttributes sectionCornerRadius];
self.layer.shadowColor = [(UICollectionSectionColorLayoutAttributes *)layoutAttributes shadowColor].CGColor;
self.layer.shadowOffset = CGSizeZero;
self.layer.shadowRadius = [(UICollectionSectionColorLayoutAttributes *)layoutAttributes shadowRadius];
self.layer.shadowOpacity = 10.f;
}
}
@end
@interface OCFTUICollectionViewLeftAlignedFlowLayout () {
NSMutableArray *_decorationViewAttrs;
}
@end
@implementation OCFTUICollectionViewLeftAlignedFlowLayout
#pragma mark - UICollectionViewLayout
- (void)prepareLayout {
[super prepareLayout];
NSInteger numberOfSections = self.collectionView.numberOfSections;
if (numberOfSections == 0) {
return;
}
[self registerClass:[UICollectionSectionColorReusableView class] forDecorationViewOfKind:kDecorationReuseIndentifier];
if (!_decorationViewAttrs) {
_decorationViewAttrs = [NSMutableArray array];
}else{
[_decorationViewAttrs removeAllObjects];
}
for (int i = 0; i < numberOfSections; i ++) {
NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:i];
if (numberOfItems == 0 || ![self.collectionView.delegate conformsToProtocol:@protocol(OCFTUICollectionViewDelegateLeftAlignedFlowLayout)]) {
continue;
}
UICollectionViewLayoutAttributes *firstAttr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:i]];
UICollectionViewLayoutAttributes *lastAttr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:numberOfItems - 1 inSection:i]];
CGRect sectionFrame = CGRectUnion(firstAttr.frame, lastAttr.frame);
sectionFrame.origin.x -= self.sectionInset.left;
sectionFrame.origin.y -= self.sectionInset.top;
if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) {
sectionFrame.size.width += self.sectionInset.left + self.sectionInset.right;
sectionFrame.size.height = self.collectionView.frame.size.height;
}else{
CGFloat itemWidth = ([UIScreen mainScreen].bounds.size.width - 32 - 7)/3.f;
if (itemWidth >= OCFTItemWidth) {
itemWidth = OCFTItemWidth;
}
sectionFrame.size.width = itemWidth * numberOfItems;
sectionFrame.size.height += self.sectionInset.top + self.sectionInset.bottom;
}
UICollectionSectionColorLayoutAttributes *decorationAttributes = [UICollectionSectionColorLayoutAttributes layoutAttributesForDecorationViewOfKind:kDecorationReuseIndentifier withIndexPath:[NSIndexPath indexPathForRow:0 inSection:i]];
decorationAttributes.frame = sectionFrame;
decorationAttributes.zIndex= -1;
decorationAttributes.tagg = 10000 + i;
UIColor *sectionBgColor = nil;
if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:backgroundColorForSection:)]) {
id delegate = (id)self.collectionView.delegate;
sectionBgColor = [delegate collectionView:self.collectionView layout:self backgroundColorForSection:i];
}
decorationAttributes.sectionBgColor = sectionBgColor;
CGFloat sectionCornerRadius = 0.f;
if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:cornerRadiusForSection:)]) {
id delegate = (id)self.collectionView.delegate;
sectionCornerRadius = [delegate collectionView:self.collectionView layout:self cornerRadiusForSection:i];
}
decorationAttributes.sectionCornerRadius = sectionCornerRadius;
UIColor *shadowColor = nil;
if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:shadowColorForSection:)]) {
id delegate = (id)self.collectionView.delegate;
shadowColor = [delegate collectionView:self.collectionView layout:self shadowColorForSection:i];
}
decorationAttributes.shadowColor = shadowColor;
CGFloat shadowRadius = 0.f;
if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:shadowRadiusForSection:)]) {
id delegate = (id)self.collectionView.delegate;
shadowRadius = [delegate collectionView:self.collectionView layout:self shadowRadiusForSection:i];
}
decorationAttributes.shadowRadius = shadowRadius;
[_decorationViewAttrs addObject:decorationAttributes];
}
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *originalAttributes = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *updatedAttributes = [NSMutableArray arrayWithArray:originalAttributes];
for (UICollectionViewLayoutAttributes *attributes in originalAttributes) {
if (!attributes.representedElementKind) {
NSUInteger index = [updatedAttributes indexOfObject:attributes];
updatedAttributes[index] = [self layoutAttributesForItemAtIndexPath:attributes.indexPath];
}
}
for (UICollectionSectionColorLayoutAttributes *attr in _decorationViewAttrs) {
if (CGRectIntersectsRect(rect, attr.frame)) {
[updatedAttributes addObject:attr];
}
}
return updatedAttributes;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes* currentItemAttributes = [[super layoutAttributesForItemAtIndexPath:indexPath] copy];
UIEdgeInsets sectionInset = [self evaluatedSectionInsetForItemAtIndex:indexPath.section];
BOOL isFirstItemInSection = indexPath.item == 0;
CGFloat layoutWidth = CGRectGetWidth(self.collectionView.frame) - sectionInset.left - sectionInset.right;
if (isFirstItemInSection) {
[currentItemAttributes ocftLeftAlignFrameWithSectionInset:sectionInset];
return currentItemAttributes;
}
NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
CGFloat previousFrameRightPoint = previousFrame.origin.x + previousFrame.size.width;
CGRect currentFrame = currentItemAttributes.frame;
CGRect strecthedCurrentFrame = CGRectMake(sectionInset.left,
currentFrame.origin.y,
layoutWidth,
currentFrame.size.height);
// if the current frame, once left aligned to the left and stretched to the full collection view
// width intersects the previous frame then they are on the same line
BOOL isFirstItemInRow = !CGRectIntersectsRect(previousFrame, strecthedCurrentFrame);
if (isFirstItemInRow) {
// make sure the first item on a line is left aligned
[currentItemAttributes ocftLeftAlignFrameWithSectionInset:sectionInset];
return currentItemAttributes;
}
CGRect frame = currentItemAttributes.frame;
frame.origin.x = previousFrameRightPoint + [self evaluatedMinimumInteritemSpacingForSectionAtIndex:indexPath.section];
currentItemAttributes.frame = frame;
return currentItemAttributes;
}
- (CGFloat)evaluatedMinimumInteritemSpacingForSectionAtIndex:(NSInteger)sectionIndex
{
if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]) {
id delegate = (id)self.collectionView.delegate;
return [delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:sectionIndex];
} else {
return self.minimumInteritemSpacing;
}
}
- (UIEdgeInsets)evaluatedSectionInsetForItemAtIndex:(NSInteger)index
{
if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
id delegate = (id)self.collectionView.delegate;
return [delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:index];
} else {
return self.sectionInset;
}
}
@end