封装自定义瀑布流,实现原理

来源:互联网 发布:数据库中范式的作用 编辑:程序博客网 时间:2024/05/17 08:12

继承UICollectionViewLayout
@interface WaterPullLayout : UICollectionViewLayout

需要两个数组来保存每个item的属性和每列的总高度

@interface WaterPullLayout (){    /**     *  保存每个item的属性     */    NSMutableArray *_itemAttributes;    /**     *  保存每列的高度     */    NSMutableArray *_columnHeights;}

.m实现必须重写四个方法:

-//对item布局,reloadData会触发- (void)prepareLayout- //返回指定区域的item的属性对象数组- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect-//返回指定indexPath的item的属性对象- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath-//collectionView的contentSize- (CGSize)collectionViewContentSize

-#import 《UIKit/UIKit.h>
@protocol WaterPullLayoutDelegate

@required
- (CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout )collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;

@end

@interface WaterPullLayout : UICollectionViewLayout

/**
* 列数
*/
@property (nonatomic) NSInteger columnCount;

/**
* 距离上下左右的距离
*/
@property (nonatomic) UIEdgeInsets sectionInsets;

/**
* 两个cell的水平方向的空隙
*/
@property (nonatomic) CGFloat horizontalSpace;

/**
* 两个cell的垂直方向的空隙
*/
@property (nonatomic) CGFloat verticalSpace;

@end

#import "WaterPullLayout.h"@interface WaterPullLayout (){    /**     *  保存每个cell的属性     */    NSMutableArray *_itemAttributes;    /**     *  保存每列的高度     */    NSMutableArray *_columnHeights;}@property (nonatomic, weak) id<WaterPullLayoutDelegate> delegate;@end@implementation WaterPullLayout- (instancetype)init{    self = [super init];    if (self)    {        //默认2列        _columnCount = 2;        _horizontalSpace = 10;        _verticalSpace = 10;        _sectionInsets = UIEdgeInsetsZero;    }    return self;}/** *  返回高度最大的列的索引 */- (NSInteger)maxHeightColumnIndex{    __block NSInteger index = 0;    __block CGFloat maxValue = 0;    [_columnHeights enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)     {         //如果从数组里面取出的元素比现有最大值还大,这个元素就是最大值         if ([obj floatValue] > maxValue)         {             //替换最大值             maxValue = [obj floatValue];             //保存最大值的索引             index = idx;         }     }];    return index;}/** *  @return 返回高度最小的列的索引 */- (NSInteger)minHeightColumnIndex{    __block NSInteger index = 0;    __block CGFloat minValue = MAXFLOAT;    [_columnHeights enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)    {        //如果从数组里面取出的元素比现有最小值还小,这个元素就是最小值        if ([obj floatValue] < minValue)        {            //替换最小值            minValue = [obj floatValue];            //保存最小值的索引            index = idx;        }    }];    return index;}//对item布局,reloadData会触发- (void)prepareLayout{    [super prepareLayout];    self.delegate = (id<WaterPullLayoutDelegate>)self.collectionView.delegate;    //初始化数组    _itemAttributes = [NSMutableArray array];    _columnHeights = [NSMutableArray array];    //初始化默认高度    for (int i = 0; i < self.columnCount; i++)    {        //每列的高度初始化都是0        _columnHeights[i] = @(0);    }    //item的宽度 =(collectionView的宽 - 左边距 - 右边距 - item间的水平间隙 )/ 列数    CGFloat itemWidth = (self.collectionView.frame.size.width - self.sectionInsets.left - self.sectionInsets.right - (self.columnCount - 1)*self.horizontalSpace)/self.columnCount;    //计算每个item的位置坐标(只考虑一个组的情况)    //[self.collectionView numberOfItemsInSection:0]返回指定组的item个数    for (int i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++)    {        //获取item大小(调用collectionView的代理方法)        CGSize size = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];        //item的高度        CGFloat itemHeight;        //item的x坐标        CGFloat xOffset;        //item的y坐标        CGFloat yOffset;        //现在图片的高度        /*         原始H    X         ---- =  ----- ===>  X = 原始H*现在W/原始W         原始W    现在W         */        itemHeight = size.height * itemWidth / size.width;        //获取列的高度的最小值索引        NSInteger minIndex = [self minHeightColumnIndex];        NSLog(@"%ld",minIndex);        //item的x坐标 = 与左边间距 + 最小高度索引值*(item宽 + item间水平间隙)        xOffset = self.sectionInsets.left + minIndex*(itemWidth+self.horizontalSpace);        //item的y坐标 = 最小高度 + (item个数如果小于列数)?与顶部间距 :item间的垂直间隙        yOffset = [_columnHeights[minIndex] floatValue] + ((i < self.columnCount) ? self.sectionInsets.top : self.verticalSpace);        //item的frame        CGRect itemFrame = CGRectMake(xOffset, yOffset, itemWidth, itemHeight);        //属性        UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];        attribute.frame = itemFrame;        //添加到数组中        [_itemAttributes addObject:attribute];        //修改当前列的高度        _columnHeights[minIndex] = @(CGRectGetMaxY(itemFrame));    }}/** *  返回指定区域的cell的属性对象数组 * *  @param rect <#rect description#> * *  @return <#return value description#> */- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{    return _itemAttributes;}/** *  返回指定indexPath的item的属性对象 * *  @param indexPath <#indexPath description#> */- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{    return _itemAttributes[indexPath.item];}/** *  collectionView的contentSize */- (CGSize)collectionViewContentSize{    //取最大值的索引    NSInteger maxIndex = [self maxHeightColumnIndex];    //返回collectionView的contentSize    return CGSizeMake(self.collectionView.frame.size.width, [_columnHeights[maxIndex] floatValue] + self.sectionInsets.bottom);}@end
0 0
原创粉丝点击