XRWaterfallLayout.m 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //
  2. // XRWaterfallLayout.m
  3. //
  4. // Created by 肖睿 on 16/3/29.
  5. // Copyright © 2016年 XR. All rights reserved.
  6. //
  7. #import "XRWaterfallLayout.h"
  8. @interface XRWaterfallLayout()
  9. //用来记录每一列的最大y值
  10. @property (nonatomic, strong) NSMutableDictionary *maxYDic;
  11. //保存每一个item的attributes
  12. @property (nonatomic, strong) NSMutableArray *attributesArray;
  13. @end
  14. @implementation XRWaterfallLayout
  15. #pragma mark- 懒加载
  16. - (NSMutableDictionary *)maxYDic {
  17. if (!_maxYDic) {
  18. _maxYDic = [[NSMutableDictionary alloc] init];
  19. }
  20. return _maxYDic;
  21. }
  22. - (NSMutableArray *)attributesArray {
  23. if (!_attributesArray) {
  24. _attributesArray = [NSMutableArray array];
  25. }
  26. return _attributesArray;
  27. }
  28. #pragma mark- 构造方法
  29. - (instancetype)init {
  30. if (self = [super init]) {
  31. self.columnCount = 2;
  32. }
  33. return self;
  34. }
  35. - (instancetype)initWithColumnCount:(NSInteger)columnCount {
  36. if (self = [super init]) {
  37. self.columnCount = columnCount;
  38. }
  39. return self;
  40. }
  41. + (instancetype)waterFallLayoutWithColumnCount:(NSInteger)columnCount {
  42. return [[self alloc] initWithColumnCount:columnCount];
  43. }
  44. #pragma mark- 相关设置方法
  45. - (void)setColumnSpacing:(NSInteger)columnSpacing rowSpacing:(NSInteger)rowSepacing sectionInset:(UIEdgeInsets)sectionInset {
  46. self.columnSpacing = columnSpacing;
  47. self.rowSpacing = rowSepacing;
  48. self.sectionInset = sectionInset;
  49. }
  50. #pragma mark- 布局相关方法
  51. //布局前的准备工作
  52. - (void)prepareLayout {
  53. [super prepareLayout];
  54. //初始化字典,有几列就有几个键值对,key为列,value为列的最大y值,初始值为上内边距
  55. for (int i = 0; i < self.columnCount; i++) {
  56. self.maxYDic[@(i)] = @(self.sectionInset.top);
  57. }
  58. //根据collectionView获取总共有多少个item
  59. NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];
  60. [self.attributesArray removeAllObjects];
  61. //为每一个item创建一个attributes并存入数组
  62. for (int i = 0; i < itemCount; i++) {
  63. UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
  64. [self.attributesArray addObject:attributes];
  65. }
  66. }
  67. //计算collectionView的contentSize
  68. - (CGSize)collectionViewContentSize {
  69. __block NSNumber *maxIndex = @0;
  70. //遍历字典,找出最长的那一列
  71. [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {
  72. if ([self.maxYDic[maxIndex] floatValue] < obj.floatValue) {
  73. maxIndex = key;
  74. }
  75. }];
  76. //collectionView的contentSize.height就等于最长列的最大y值+下内边距
  77. return CGSizeMake(0, [self.maxYDic[maxIndex] floatValue] + self.sectionInset.bottom);
  78. }
  79. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
  80. //根据indexPath获取item的attributes
  81. UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
  82. //获取collectionView的宽度
  83. CGFloat collectionViewWidth = self.collectionView.frame.size.width;
  84. //item的宽度 = (collectionView的宽度 - 内边距与列间距) / 列数
  85. CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount;
  86. CGFloat itemHeight = 0;
  87. //获取item的高度,由外界计算得到
  88. if (self.itemHeightBlock) itemHeight = self.itemHeightBlock(itemWidth, indexPath);
  89. else {
  90. if ([self.delegate respondsToSelector:@selector(waterfallLayout:itemHeightForWidth:atIndexPath:)])
  91. itemHeight = [self.delegate waterfallLayout:self itemHeightForWidth:itemWidth atIndexPath:indexPath];
  92. }
  93. //找出最短的那一列
  94. __block NSNumber *minIndex = @0;
  95. [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {
  96. if ([self.maxYDic[minIndex] floatValue] > obj.floatValue) {
  97. minIndex = key;
  98. }
  99. }];
  100. //根据最短列的列数计算item的x值
  101. CGFloat itemX = self.sectionInset.left + (self.columnSpacing + itemWidth) * minIndex.integerValue;
  102. //item的y值 = 最短列的最大y值 + 行间距
  103. CGFloat itemY = [self.maxYDic[minIndex] floatValue] + self.rowSpacing;
  104. //设置attributes的frame
  105. attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);
  106. //更新字典中的最大y值
  107. self.maxYDic[minIndex] = @(CGRectGetMaxY(attributes.frame));
  108. return attributes;
  109. }
  110. //返回rect范围内item的attributes
  111. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
  112. return self.attributesArray;
  113. }
  114. @end