美文网首页
iOS 瀑布流

iOS 瀑布流

作者: 小啦啦啦熊 | 来源:发表于2016-07-23 11:22 被阅读0次

    下面这些是外部封装的接口:

    @interface LRBWaterFallLayout : UICollectionViewLayout

    @property (nonatomic) NSMutableArray * modelAry;

    /**

    *  最小行间距

    */

    @property (nonatomic) CGFloat minimumLineSpacing;

    /**

    *  最小item之间的距离

    */

    @property (nonatomic) CGFloat minimumInteritemSpacing;

    /**

    *  内边距

    */

    @property (nonatomic) UIEdgeInsets sectionInset;

    /**

    *  总列数

    */

    @property (nonatomic) NSUInteger columns;

    @end

    下面这些是那些常规的方法

    //屏幕bounds#define SCREEN_BOUNSE ([UIScreen mainScreen].bounds)

    //屏幕宽度#define SCREEN_WIDTH  (SCREEN_BOUNSE.size.width)

    @interface LRBWaterFallLayout ()

    /** *  记录每一列的高度 */

    @property (nonatomic) NSMutableArray *heightArray;

    /** *  记录每一个item的属性 */

    @property (nonatomic) NSMutableArray *attrArray;

    @end

    @implementation LRBWaterFallLayout

    //重写方法

    //准备布局,布局之前准备工作全部做完

    - (void)prepareLayout{    

    //1.创建高度数组    

    if (self.heightArray == nil) {        

    //没有数组创建数组        

    self.heightArray = [NSMutableArray array];   

     }else{        

    //有数组将原来数组里面的内容全部清空        

    [self.heightArray removeAllObjects];    

    }        

    if (self.attrArray == nil) {        

    self.attrArray = [NSMutableArray array];   

     }else{       

     [self.attrArray removeAllObjects];   

     }       

     //2.初始化高度数组    

    for (int i = 0; i < self.columns; i++) {        

    [self.heightArray addObject:@(self.sectionInset.top)];   

     }        

    //3.计算item的宽度   

     CGFloat totalWidth = SCREEN_WIDTH;    

    CGFloat validWidth = totalWidth - self.sectionInset.left - self.sectionInset.right - (self.columns - 1) * self.minimumInteritemSpacing;   

     CGFloat itemWidth = validWidth / self.columns;        

    //4.开始布局每个item    

    //取出item的总个数   

     NSUInteger totalCount = [self.collectionView numberOfItemsInSection:0];   

     for (int i = 0; i < totalCount; i++) {       

     //取出最短列的下标        

    NSUInteger minIndex = [self minIndexOfColumn];        

    //求item的x坐标        

    CGFloat itemX = self.sectionInset.left + minIndex * (itemWidth + self.minimumInteritemSpacing);       

     //求item的y坐标       

     CGFloat itemY = [self.heightArray[minIndex] floatValue];       

     //得到item的高度       

     LRBFirstOneItemOfPicsModel * oneItems = self.modelAry[i];        LRBFirstInfoModel * firstInfo = oneItems.data.info;       

     CGFloat rate = [firstInfo.img_h floatValue] / [firstInfo.img_w floatValue];        CGFloat itemHeight = itemWidth * rate + 20;        

    //创建item的属性对象        

    NSIndexPath *itemIndexPath = [NSIndexPath indexPathForItem:i inSection:0];        UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:itemIndexPath];       

     //将item的frame存放到item的属性对象中       

     attr.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);        

    //将item属性对象,存放到属性数组中        

    [self.attrArray addObject:attr];               

     //更新高度数组中的高度      

     CGFloat height = [self.heightArray[minIndex] floatValue] + itemHeight + self.minimumLineSpacing ;       

     [self.heightArray replaceObjectAtIndex:minIndex withObject:@(height)];   

     }

    }

    //重写方法

    //所有的item的属性对象,只要frame和rect有交集,这些属性对象我都要,将其存放到数组中返回

    - (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect

    {

    //存放所有和rect有交集的item属性对象

    NSMutableArray *mulArray = [NSMutableArray array];

    for (UICollectionViewLayoutAttributes *attr in self.attrArray) {

    //判断每一个attr的frame和rect是否有交集,如果有交集的话存放到数组中

    if (CGRectIntersectsRect(attr.frame, rect)) {

    [mulArray addObject:attr];

    }

    }

    return mulArray;

    }

    //重写方法

    //返回集合视图的内容尺寸

    - (CGSize)collectionViewContentSize

    {

    //得到所有列中最高列的下标

    NSUInteger maxIndex = [self maxIndexOfColumn];

    //获取内容尺寸的最大值

    CGFloat height = [self.heightArray[maxIndex] floatValue] + self.sectionInset.bottom;

    //每一个布局对象里面都有一个指针指向当前集合视图,可以通过这个指针拿到当前集合视图

    CGFloat width = SCREEN_WIDTH;

    //返回集合视图的内容尺寸

    return CGSizeMake(width, height);

    }

    - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

    {

    return YES;

    }

    //每列中最短列的下标

    - (NSUInteger)minIndexOfColumn

    {

    NSUInteger index = 0;

    for (int i = 1; i < self.heightArray.count; i++) {

    if ([self.heightArray[index] floatValue] > [self.heightArray[i] floatValue]) {

    index = i;

    }

    }

    return index;

    }

    //每列中最长列的下标

    - (NSUInteger)maxIndexOfColumn

    {

    NSUInteger index = 0;

    for (int i = 1; i < self.heightArray.count; i++) {

    if ([self.heightArray[index] floatValue] < [self.heightArray[i] floatValue]) {

    index = i;

    }

    }

    return index;

    }

    @end

    然而只有上面的这些的时候,在一开始就将item的个数确定,以及不需要复用的时候是可行的。在需要复用的时候,会出错,错误提示为:*** Assertion failure in -[UICollectionViewData layoutAttributesForItemAtIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.30.14/UICollectionViewData.m:666

    为了解决上述问题,实现方法[UICollectionViewData layoutAttributesForItemAtIndexPath:],对每个item的属性进行设置,即可解决,实现方法如下:

    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

    {

    UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    CGFloat totalWidth = SCREEN_WIDTH;

    CGFloat validWidth = totalWidth - self.sectionInset.left - self.sectionInset.right - (self.columns - 1) * self.minimumInteritemSpacing;

    CGFloat itemWidth = validWidth / self.columns;

    NSUInteger minIndex = [self minIndexOfColumn];

    //求item的x坐标

    CGFloat itemX = self.sectionInset.left + minIndex * (itemWidth + self.minimumInteritemSpacing);

    //求item的y坐标

    CGFloat itemY = [self.heightArray[minIndex] floatValue];

    LRBFirstOneItemOfPicsModel * oneItems = self.modelAry[indexPath.row];

    LRBFirstInfoModel * firstInfo = oneItems.data.info;

    CGFloat rate = [firstInfo.img_h floatValue] / [firstInfo.img_w floatValue];

    CGFloat itemHeight = itemWidth * rate + 20;

    attr.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);

    return attr;

    }

    在使用storyboard拉出来的collectionView的时候,进行布局,可采用下述方法进行调用以实现瀑布流:

    weakSelf.collectionV.collectionViewLayout = [self waterFallLayout];

    - (UICollectionViewLayout *)waterFallLayout{

    LRBWaterFallLayout * layout = [[LRBWaterFallLayout alloc] init];

    layout.minimumInteritemSpacing = 10;

    layout.minimumLineSpacing = 10;

    layout.columns = 2;

    layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);

    layout.modelAry = _dataSource;

    return layout;

    }

    相关文章

      网友评论

          本文标题:iOS 瀑布流

          本文链接:https://www.haomeiwen.com/subject/jyqwjttx.html