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;
}