美文网首页
iOS 瀑布流Layout 实现逻辑(面试题)

iOS 瀑布流Layout 实现逻辑(面试题)

作者: 9岁就很6 | 来源:发表于2019-06-17 19:29 被阅读0次

    前言

    笔者上周去找工作的时候,遇到一个面试问题,那就是:“你知道瀑布流具体是怎么实现的吗?”,当时回答的不是很好,所以打算整理一份写在简书,有需要的同行可以学习下,现在分享给大家~

    一、 创建一个自定义UICollectionViewLayout 的类 Customlayout

    点h

    @interface Customlayout : UICollectionViewLayout
    
    //宽度
    @property(nonatomic,assign)float itemWidth;
    //列数
    @property(nonatomic,assign)NSInteger columuCount;
    //间隙
    @property(nonatomic,assign)UIEdgeInsets insets;
    
    @property(nonatomic,assign)NSInteger ietmCounts;
    
    @property(nonatomic,assign)id delegate;
    
    @end
    @protocol customlayouDelegate <NSObject>
    //宽高比例公式: ((屏幕宽-间距)/item个数)*服务端高/服务端宽 
    //请求服务端后,传入高度进行赋值重绘item;
    -(CGFloat)getHeightWithIndexPath:(NSIndexPath *)indexPath;
     
    @end
    

    可以回答说有几个必须要实现重写的系统方法

    #pragma mark  将要布局的时候,做一些准备工作
    -(void)prepareLayout{}
    
    #pragma mark  返回和屏幕相交的cell
    - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{}
    
    #pragma mark   计算容量
    -(CGSize)collectionViewContentSize{}
    
    #pragma mark 计算最高的那一列
    #pragma mark 计算最短的那一列
    
    

    点m

    #import “Customlayout.h"
    
    @interface Customlayout ()
    
    //缓存数据
    @property(nonatomic,retain)NSMutableArray * heightArr;
    //每个item 的富文本属性
    @property(nonatomic,retain)NSMutableArray * attributesArr;
    //cell之间的间隙
    @property(nonatomic,assign)float itemSpace;
    
    
    @end
    
    @implementation Customlayout
    
    #pragma mark  将要布局的时候,做一些准备工作
    -(void)prepareLayout{
        [super prepareLayout];
        //计算中间一块的间隙=屏幕的宽  - (左+右间隙)
        float middleWidth = [UIScreen mainScreen].bounds.size.width - (_insets.left+_insets.right);
        
       //cell之间的间隙 = 宽度*4个+间隙*3 = middle
        _itemSpace = (middleWidth - _columuCount*_itemWidth)/(_columuCount -1);
        
        //记得初始化
        _heightArr = [[NSMutableArray alloc]init];
        _attributesArr = [[NSMutableArray alloc]init];
        //循环列数
        for (int i =0; i<_columuCount; i++) {
            [_heightArr addObject:@(0)];
        }
        
        //获取view在当前区的item的个数
        _ietmCounts = [self.collectionView numberOfItemsInSection:0];
        
    
        for (int i =0; i<_ietmCounts; i++) {
            
            NSIndexPath * indexPath = [NSIndexPath indexPathForRow:i inSection:0];
            
            
            NSInteger  index = [self shortColumn];
            //index * (width +space)+left 
            //索引 x (宽度+间隙) +左边
            float x = _insets.left +(_itemWidth + _itemSpace)*index;
            float y =[_heightArr[index]floatValue];
            
            float height = [_delegate getHeightWithIndexPath:indexPath];
            
            
            UICollectionViewLayoutAttributes * attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
            //单元格
            attributes.frame =CGRectMake(x, y, _itemWidth, height);
            
            [_attributesArr addObject:attributes];
            //重置Height
                                 
            _heightArr[index] =@(y+height+_itemSpace);
        }
    
    }
    #pragma mark返回和屏幕相交的cell
    - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
        
        NSPredicate * predicate = [NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes * attributes, NSDictionary<NSString *,id> * _Nullable bindings) {
            //相交
            return CGRectIntersectsRect(attributes.frame, rect);
        }];
        //过滤数组
        return [_attributesArr filteredArrayUsingPredicate:predicate];
        
    }
    #pragma mark 计算容量
    -(CGSize)collectionViewContentSize{
        NSInteger index =[self longColumn];
        
        float height = [_heightArr[index] floatValue];
        return  CGSizeMake(self.collectionView.frame.size.width, height);
        
        
    }
    #pragma mark 计算最短的索引
    -(NSInteger)shortColumn{
         
        __block float height = LONG_MAX;
        __block NSInteger index = 0;
        [_heightArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (height>[obj floatValue]) {
                
                //只要找到比heighte还小的,就替换下
                height = [obj floatValue];
                index = idx;
            }
            
        }];
        return index;
    }
    #pragma mark 计算最高的那一列
    -(NSInteger)longColumn{
      __block  float height = 0;
       __block NSInteger index =0;
        [_heightArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (height >[obj floatValue]) {
                height = [obj floatValue];
                index = idx;
            }
            
        }];
        
        return index;
        
        
    }
    @end
    

    二、实现

        Customlayout * layout = [[Customlayout alloc]init];
        layout.delegate =self;
        layout.insets =UIEdgeInsetsMake(10, 10, 10, 10);//间隙
        layout.itemWidth = ([UIScreen mainScreen].bounds.size.width-30)/2.0; //item大小
        layout.columuCount = 2; //比如2列
     
        _collectionView = [[UICollectionView alloc]initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
        _collectionView.delegate=self;
        _collectionView.dataSource=self;
        [self.view addSubview:_collectionView];
    

    实现代理

    -(CGFloat)getHeightWithIndexPath:(NSIndexPath *)indexPath{
        NSDictionary *dic = _sourceArr[indexPath.item];
        float width = [dic[@"width"] floatValue];
        float height = [dic[@"height"] floatValue];
        
        return ((UIScreen mainScreen].bounds.size.width-30)/2.0)*height/width + 20;
    }
    
    

    希望大家面试少点坑,多了解下原理哈~加油~

    相关文章

      网友评论

          本文标题:iOS 瀑布流Layout 实现逻辑(面试题)

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