// // LBKeyWordLayout.m // IphoneBIMe // // Created by ZhangJF on 2023/3/9. // Copyright © 2023 ProBIM. All rights reserved. // #import "LBKeyWordLayout.h" @interface LBKeyWordLayout() @property (strong, nonatomic) NSCache *cache; @end @implementation LBKeyWordLayout - (void)prepareLayout { [super prepareLayout]; self.cache = [NSCache new]; } - (void)invalidateLayout { [super invalidateLayout]; self.cache = [NSCache new]; } - (BOOL)shouldInvalidateLayoutForPreferredLayoutAttributes:(UICollectionViewLayoutAttributes *)preferredAttributes withOriginalAttributes:(UICollectionViewLayoutAttributes *)originalAttributes { return YES; } - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES; } - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray *attributes = [super layoutAttributesForElementsInRect:rect].copy; return [self layoutAttributesForElements:attributes]; } - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self attributesAtIndexPath:indexPath]; } #pragma mark - Private - (NSArray *)layoutAttributesForElements:(NSArray *)attributes { NSMutableArray *alignedAttributes = [NSMutableArray new]; for (UICollectionViewLayoutAttributes *item in attributes) { if(item.representedElementKind != nil) { [alignedAttributes addObject:item]; } else { [alignedAttributes addObject:[self layoutAttributesForItem:item atIndexPath:item.indexPath]]; } } return alignedAttributes.copy; } - (UICollectionViewLayoutAttributes *)layoutAttributesForItem:(UICollectionViewLayoutAttributes *)attributes atIndexPath:(NSIndexPath *)indexPath { return [self attributes:attributes atIndexPath:indexPath]; } - (UICollectionViewLayoutAttributes *)attributesAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath].copy; return [self attributes:attributes atIndexPath:indexPath]; } - (UICollectionViewLayoutAttributes *)attributes:(UICollectionViewLayoutAttributes *)attributes atIndexPath:(NSIndexPath *)indexPath { if ([self.cache objectForKey:indexPath]) { return [self.cache objectForKey:indexPath]; } NSMutableArray *itemsInRow = [NSMutableArray array]; const NSInteger totalInSection = [self.collectionView numberOfItemsInSection:indexPath.section]; const CGFloat width = CGRectGetWidth(self.collectionView.bounds); const CGRect rowFrame = CGRectMake(0, CGRectGetMinY(attributes.frame), width, CGRectGetHeight(attributes.frame)); // Go forward to the end or the row or section items NSInteger index = indexPath.row; while(index++ < totalInSection - 1) { UICollectionViewLayoutAttributes *next = [super layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:indexPath.section]].copy; if (!CGRectIntersectsRect(next.frame, rowFrame)) { break; } [itemsInRow addObject:next]; } // Current item [itemsInRow addObject:attributes]; // Go backward to the start of the row or first item index = indexPath.row; while (index-- > 0) { UICollectionViewLayoutAttributes *prev = [super layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:indexPath.section]].copy; if (!CGRectIntersectsRect(prev.frame, rowFrame)) { break; } [itemsInRow addObject:prev]; } // Total items width include spacings CGFloat totalWidth = self.minimumInteritemSpacing * (itemsInRow.count - 1); for (UICollectionViewLayoutAttributes *item in itemsInRow) { totalWidth += CGRectGetWidth(item.frame); } // Correct sorting in row [itemsInRow sortUsingComparator:^NSComparisonResult(UICollectionViewLayoutAttributes *obj1, UICollectionViewLayoutAttributes *obj2) { return obj1.indexPath.row > obj2.indexPath.row; }]; CGRect rect = CGRectZero; for (UICollectionViewLayoutAttributes *item in itemsInRow) { CGRect frame = item.frame; CGFloat x = frame.origin.x; if (CGRectIsEmpty(rect)) { x = self.sectionInset.left; } else { x = CGRectGetMaxX(rect) + self.minimumInteritemSpacing; } frame.origin.x = x; item.frame = frame; rect = frame; [self.cache setObject:item forKey:item.indexPath]; } [self.cache setObject:attributes forKey:indexPath]; return attributes; } @end