简介瀑布流的实现

2016-09-10  本文已影响0人  BrightFuture

思路

步骤

protocol UICollectionViewWaterLayoutDelegate <NSObject>
  @required
  // 返回item的高度(根据width按比例去计算)
  - (CGFloat)waterLayout:(UICollectionViewWaterLayout *)waterLayout heightForItemAtIndexPath:(NSIndexPath *)indexPath andWidth:(CGFloat)width;
  @optional
  // 返回列数
  - (NSInteger)numberOfColumnsInWaterLayout:(UICollectionViewWaterLayout *)waterLayout;
  // 返回行间距
  - (CGFloat)rowMarginForWaterLayout:(UICollectionViewWaterLayout *)waterLayout;
  // 返回列间距
  - (CGFloat)columnMarginForWaterLayout:(UICollectionViewWaterLayout *)waterLayout;
  // 返回内边距
  - (UIEdgeInsets)edgeInsetsForWaterLayout:(UICollectionViewWaterLayout *)waterLayout;
@end
 /** 缓存每个item的UICollectionViewLayoutAttributes属性,避免重复计算 */
property (nonatomic, strong) NSMutableArray *attributesArr;
/** 记录每列的高度 */
property (nonatomic, strong) NSMutableArray *columnHeights;
  - (void)prepareLayout { 
    // 要先调用父类的prepareLayout 
    [super prepareLayout]; 
    // 清空原来缓存的列的高度和cell的未知属性,否则当重新调用prepareLayout,会累加 
    [self.attributesArr removeAllObjects]; 
    [self.columnHeights removeAllObjects]; 
    // 设置列高度初始值为顶部内边距 
    for (int i = 0; i < layoutColumn; i++) {
       [self.columnHeights addObject:[NSNumber numberWithDouble:layoutInsets.top]];
     } 
    // 设置每个item的布局属性,并缓存 
    NSInteger itemsTotal = [self.collectionView numberOfItemsInSection:0];
    for (int i = 0; i < itemsTotal; i++) { 
      NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
      UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 
      attributes.frame = [self getItemFrameWithIndexPath:indexPath]; [self.attributesArr addObject:attributes]; 
    }
}
  /** 每个item都是放到当前高度最低的列下面 
    * 要计算x,y,就要找到高度最低的列 
    * 宽度 = (collectionView宽度 - 左内边距 - 右内边距 - (列数 - 1)*列间距)/列数 * 高度通过代理获取 
    * x = 左内边距 + 列号 * (宽度 + 列间距) 
    * y = 列的高度 + 行间距 
    */
   - (CGRect)getItemFrameWithIndexPath:(NSIndexPath *)indexPath { 
    // 高度最低的列 
    CGFloat minHeight = [self.columnHeights[0] doubleValue]; 
    NSInteger minHeightCol = 0;
    for (int i = 1; i < self.columnHeights.count; i++) { 
      CGFloat columnHeight = [self.columnHeights[i] doubleValue]; 
      if (minHeight > columnHeight) { 
        minHeight = columnHeight; minHeightCol = i; 
      } 
    }  
    // 计算item的位置 
    CGFloat collectionViewW = self.collectionView.frame.size.width;
    CGFloat itemW = (collectionViewW - self.insets.left - self.insets.right - (self.columns - 1)*self.columnMargin) / self.columns; 
    // 通过使用者实现的代理拿到item的高度
    CGFloat itemH = [self.delegate waterLayout:self heightForItemAtIndexPath:indexPath andWidth:itemW]; 
    CGFloat itemX = (itemW + self.columnMargin) * minHeightCol; 
    CGFloat itemY = minHeight + self.rowMargin; CGRect frame = CGRectMake(itemX, itemY, itemW, itemH);  
   // 更新列的高度 
    self.columnHeights[minHeightCol] = [NSNumber numberWithDouble:CGRectGetMaxY(frame)];  
    return frame;
}
  - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { 
    return self.attributesArr;
  }
  - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { 
    return self.attributesArr[indexPath.item];
  }
  - (CGSize)collectionViewContentSize { 
    // 找到高度最高的列 
    // 滚动高度 = 高度最高的列的高度 + 底部内边距 
    // 记录最低高度
    CGFloat maxHeight = [self.columnHeights[0] doubleValue];
    for(int i = 1; i < self.columnHeights.count; i++) { 
      CGFloat columnHeight = [self.columnHeights[i] doubleValue]; 
      if (maxHeight < columnHeight) { 
        maxHeight = columnHeight;
      }
    }
   return CGSizeMake(0, maxHeight + layoutInsets.bottom);
  }
上一篇 下一篇

猜你喜欢

热点阅读