BYHLabelsLayout.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. //
  2. // BYHLabelsLayout.m
  3. // UICollectionVIewDemo
  4. //
  5. // Created by 疯叶 on 2019/8/14.
  6. // Copyright © 2019 疯叶. All rights reserved.
  7. //
  8. #import "BYHLabelsLayout.h"
  9. /** 每一列之间的间距 */
  10. static const CGFloat BYHMinimumLineSpacing = 10;
  11. /** 每一行之间的间距 */
  12. static const CGFloat BYHMinimumInterSpacing = 10;
  13. /** 边缘间距 */
  14. static const UIEdgeInsets XHLDefaultEdgeInsets = {10, 10, 10, 10};
  15. /** 头部高度 */
  16. static const CGFloat BYHHeaderHeight = 0;
  17. /** 尾部高度 */
  18. static const CGFloat BYHFooterHeight = 0;
  19. @interface BYHLabelsLayout ()
  20. /** 存放所有cell的布局属性 */
  21. @property (nonatomic, strong) NSMutableArray *itemAttrsArray;
  22. /** 存放所有Header的布局属性 */
  23. @property (nonatomic, strong) NSMutableArray *headerAttrsArr;
  24. /** 存放所有Footer的布局属性 */
  25. @property (nonatomic, strong) NSMutableArray *footerAttrsArr;
  26. /** 存放所有列的当前高度 */
  27. @property (nonatomic, strong) NSMutableArray *columnHeights;
  28. /** 内容的高度 */
  29. @property (nonatomic, assign) CGFloat contentHeight;
  30. /** 内容的宽度 */
  31. @property (nonatomic, assign) CGFloat itemMaxX;
  32. /** item的最大高度 */
  33. @property (nonatomic, assign) CGFloat itemMaxHeight;
  34. /** 上次布局的section*/
  35. @property (nonatomic, assign) NSInteger nextSection;
  36. @end
  37. @implementation BYHLabelsLayout
  38. #pragma mark - 代理数据处理
  39. - (CGFloat)minimumInterWithSection:(NSInteger)section {
  40. if ([self.delegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) {
  41. return [self.delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:section];
  42. } else {
  43. return BYHMinimumInterSpacing;
  44. }
  45. }
  46. - (CGFloat)minimumLineWithSection:(NSInteger)section {
  47. if ([self.delegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]) {
  48. return [self.delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:section];
  49. } else {
  50. return BYHMinimumLineSpacing;
  51. }
  52. }
  53. - (UIEdgeInsets)edgeInsetsWithSection:(NSInteger )section {
  54. if (section < 0) {
  55. return UIEdgeInsetsZero;
  56. }
  57. if ([self.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
  58. return [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:section];
  59. } else {
  60. return XHLDefaultEdgeInsets;
  61. }
  62. }
  63. - (CGFloat)headerHeightWithSection:(NSInteger)section {
  64. if ([self.delegate respondsToSelector:@selector(collectionView:layout:referenceHeightForHeaderInSection:)]) {
  65. return [self.delegate collectionView:self.collectionView layout:self referenceHeightForHeaderInSection:section];
  66. }
  67. return BYHHeaderHeight;
  68. }
  69. - (CGFloat)footerHeightWithSection:(NSInteger)section {
  70. if ([self.delegate respondsToSelector:@selector(collectionView:layout:referenceHeightForFooterInSection:)]) {
  71. return [self.delegate collectionView:self.collectionView layout:self referenceHeightForFooterInSection:section];
  72. }
  73. return BYHFooterHeight;
  74. }
  75. /**
  76. * 初始化
  77. */
  78. - (void)prepareLayout
  79. {
  80. [super prepareLayout];
  81. self.itemAttrsArray = [NSMutableArray array];
  82. self.headerAttrsArr = [NSMutableArray array];
  83. self.footerAttrsArr = [NSMutableArray array];
  84. CGFloat collectionViewW = self.collectionView.frame.size.width;
  85. // 清除之前所有的布局属性
  86. [self.itemAttrsArray removeAllObjects];
  87. [self.headerAttrsArr removeAllObjects];
  88. [self.footerAttrsArr removeAllObjects];
  89. NSInteger sectionNum = [self.collectionView numberOfSections];
  90. for (NSInteger section = 0; section < sectionNum; section++) {
  91. UIEdgeInsets sectionInset = [self edgeInsetsWithSection:section];
  92. CGFloat minimumzLine = [self minimumLineWithSection:section];
  93. CGFloat minimumzInter = [self minimumInterWithSection:section];
  94. self.itemMaxX = sectionInset.left - minimumzLine;
  95. UICollectionViewLayoutAttributes *headerAttrs = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
  96. CGFloat headerHeight = [self headerHeightWithSection:section];
  97. headerAttrs.frame = CGRectMake(0, self.itemMaxHeight, collectionViewW, headerHeight);
  98. [self.headerAttrsArr addObject:headerAttrs];
  99. self.itemMaxHeight = self.itemMaxHeight + headerHeight + sectionInset.top;
  100. NSInteger itemNum = [self.collectionView numberOfItemsInSection:section];
  101. NSMutableArray *sectionItemArr = [NSMutableArray array];
  102. for (NSInteger item = 0; item < itemNum; item++) {
  103. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
  104. CGSize itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
  105. UICollectionViewLayoutAttributes *itemAttrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
  106. if (itemSize.width >= (collectionViewW - sectionInset.left - sectionInset.right)) {
  107. if (item != 0) {
  108. self.itemMaxHeight = self.itemMaxHeight + minimumzInter;
  109. }
  110. self.itemMaxX = sectionInset.left;
  111. itemAttrs.frame = CGRectMake(self.itemMaxX, self.itemMaxHeight, itemSize.width, itemSize.height);
  112. self.itemMaxHeight = self.itemMaxHeight + itemSize.height + minimumzInter;
  113. }else {
  114. if (collectionViewW - self.itemMaxX - sectionInset.right - minimumzLine >= itemSize.width) {
  115. self.itemMaxX += minimumzLine;
  116. }else {
  117. self.itemMaxX = sectionInset.left;
  118. self.itemMaxHeight = self.itemMaxHeight + minimumzInter + itemSize.height;
  119. }
  120. itemAttrs.frame = CGRectMake(self.itemMaxX, self.itemMaxHeight, itemSize.width, itemSize.height);
  121. self.itemMaxX += itemSize.width;
  122. }
  123. if (item == itemNum - 1) {
  124. self.itemMaxHeight = self.itemMaxHeight + itemSize.height + sectionInset.bottom;
  125. }
  126. [sectionItemArr addObject:itemAttrs];
  127. }
  128. [self.itemAttrsArray addObject:sectionItemArr];
  129. UICollectionViewLayoutAttributes *footerAttrs = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
  130. CGFloat footerHeight = [self footerHeightWithSection:section];
  131. [self.footerAttrsArr addObject:footerAttrs];
  132. footerAttrs.frame = CGRectMake(0, self.itemMaxHeight, collectionViewW, footerHeight);
  133. self.itemMaxHeight = self.itemMaxHeight + footerHeight;
  134. self.contentHeight = self.itemMaxHeight;
  135. }
  136. }
  137. /**
  138. * 决定cell的排布
  139. */
  140. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
  141. // return self.itemAttrsArray;
  142. NSMutableArray<UICollectionViewLayoutAttributes *> *result = [NSMutableArray array];
  143. [_itemAttrsArray enumerateObjectsUsingBlock:^(NSMutableArray<UICollectionViewLayoutAttributes *> *layoutAttributeOfSection, NSUInteger idx, BOOL *stop) {
  144. [layoutAttributeOfSection enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *attribute, NSUInteger idx, BOOL *stop) {
  145. if (CGRectIntersectsRect(rect, attribute.frame)) {
  146. [result addObject:attribute];
  147. }
  148. }];
  149. }];
  150. [_headerAttrsArr enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *attribute, NSUInteger idx, BOOL *stop) {
  151. if (attribute.frame.size.height && CGRectIntersectsRect(rect, attribute.frame)) {
  152. [result addObject:attribute];
  153. }
  154. }];
  155. [_footerAttrsArr enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *attribute, NSUInteger idx, BOOL *stop) {
  156. if (attribute.frame.size.height && CGRectIntersectsRect(rect, attribute.frame)) {
  157. [result addObject:attribute];
  158. }
  159. }];
  160. return result;
  161. }
  162. /**
  163. * 返回indexPath位置cell对应的布局属性
  164. */
  165. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
  166. return self.itemAttrsArray[indexPath.section][indexPath.item];
  167. }
  168. - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath {
  169. if ([elementKind isEqualToString:UICollectionElementKindSectionHeader]) {
  170. NSLog(@"Header: section-%zd, item-%zd", indexPath.section, indexPath.item);
  171. return self.headerAttrsArr[indexPath.item];
  172. }
  173. if ([elementKind isEqualToString:UICollectionElementKindSectionFooter]) {
  174. NSLog(@"Footer: section-%zd, item-%zd", indexPath.section, indexPath.item);
  175. return self.footerAttrsArr[indexPath.item];
  176. }
  177. return nil;
  178. }
  179. - (CGSize)collectionViewContentSize {
  180. return CGSizeMake(CGRectGetWidth(self.collectionView.bounds), self.contentHeight);
  181. }
  182. @end