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

2019-06-17  本文已影响0人  9岁就很6

前言

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

一、 创建一个自定义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;
}

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

上一篇下一篇

猜你喜欢

热点阅读