Mas_Tan

Site blog for Tan

No Praise For Colorful


Welcome To My Blog

UICollectionView 瀑布流

UICollectionView 瀑布流的实现

UICollectionView 比 tableView 灵活,功能也强大很多。系统实现了流式布局,但用处还有很多限制。

要想实现更灵活的布局,就咬重写UICollectionViewLayout。

Demo地址:WaterfallCollectionLayout

先看下实现效果:

image.png

废话不多说,直接上代码:

先看WaterfallCollectionLayout.m

	#import "WaterfallCollectionLayout.h"
	#define colMargin 5
	#define colCount 4
	#define rolMargin 5
	@interface WaterfallCollectionLayout ()
	//数组存放每列的总高度
	@property(nonatomic,strong)NSMutableArray* colsHeight;
	//单元格宽度
	@property(nonatomic,assign)CGFloat colWidth;
	@end
	该类要重写以下方法:
	
	//完成布局前的初始工作
	-(void)prepareLayout;
	
	//collectionView的内容尺寸
	-(CGSize)collectionViewContentSize;
	
	//为每个item设置属性
	-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
	
	//获取制定范围的所有item的属性
	-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
	
	-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
	每次调用会清空colsHeight数组里的信息:
	
	//完成布局前的初始工作
	-(void)prepareLayout{
		[super prepareLayout];
		self.colWidth =( self.collectionView.frame.size.width - (colCount+1)*colMargin )/colCount;
		//让它重新加载
		self.colsHeight = nil;
	}
	//通过遍历colHeight数组里的所有列来获得最长的那一列,返回contentsize
	//collectionView的内容尺寸
	-(CGSize)collectionViewContentSize{
		NSNumber * longest = self.colsHeight[0];
		for (NSInteger i =0;i<self.colsHeight.count;i++) {
			NSNumber* rolHeight = self.colsHeight[i];
			if(longest.floatValue<rolHeight.floatValue){
				longest = rolHeight;
			}
		}
		return CGSizeMake(self.collectionView.frame.size.width, longest.floatValue);
	}

每个cell要出来时这个方法会被调用,在此方法中设置该cell的frame。

注意heightBlock是外部控制器传进来的block用以计算每个cell的高度,现在我只是设置了随机数。如果没有传block进来我这里直接让他崩溃了。

为每个item设置属性

	-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
		UICollectionViewLayoutAttributes* attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
		NSNumber * shortest = self.colsHeight[0];
		NSInteger  shortCol = 0;
		for (NSInteger i =0;i<self.colsHeight.count;i++) {
			NSNumber* rolHeight = self.colsHeight[i];
			if(shortest.floatValue>rolHeight.floatValue){
			shortest = rolHeight;
			shortCol=i;
			}
		}
		CGFloat x = (shortCol+1)*colMargin+ shortCol * self.colWidth;
		CGFloat y = shortest.floatValue+colMargin;
		
		//获取cell高度
		CGFloat height=0;
		NSAssert(self.heightBlock!=nil, @"未实现计算高度的block ");
		if(self.heightBlock){
			height = self.heightBlock(indexPath);
		}
		attr.frame= CGRectMake(x, y, self.colWidth, height);
		self.colsHeight[shortCol]=@(shortest.floatValue+colMargin+height);
		
		return attr;
	}

获取所有item的属性

	-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
		NSMutableArray* array = [NSMutableArray array];
		NSInteger items = [self.collectionView numberOfItemsInSection:0];
		for (int i = 0; i<items;i++) {
			UICollectionViewLayoutAttributes* attr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
			[array addObject:attr];
		}
		return array;
	}

实现下列方法会在出现新的cell时重新布局并调用preparelayout方法

	-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
	return YES;
	}

每列高度的存放,初始高度可以改,我这里是0

	-(NSMutableArray *)colsHeight{
		if(!_colsHeight){
			NSMutableArray * array = [NSMutableArray array];
			for(int i =0;i<colCount;i++){
				//这里可以设置初始高度
				[array addObject:@(0)];
			}
			_colsHeight = [array mutableCopy];
		}
		return _colsHeight;
	}

再来看看控制器里就是这么简单

#pragma mark getter-setter
-(UICollectionView *)collectionView{
	if(!_collectionView){
		_collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:self.layout];
		_collectionView.backgroundColor = [UIColor whiteColor];
		_collectionView.delegate=self;
		_collectionView.dataSource=self;
		[_collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:identifer];
	}
	return _collectionView;
}
-(UICollectionViewLayout *)layout{
	if(!_layout){
		_layout = [[WaterfallCollectionLayout alloc]initWithItemsHeightBlock:^CGFloat(NSIndexPath *index) {
		return [self.heightArr[index.item] floatValue];
		}];
	}
	return _layout;
}
-(NSArray *)heightArr{
	if(!_heightArr){
		//随机生成高度
		NSMutableArray *arr = [NSMutableArray array];
		for (int i = 0; i<100; i++) {
			[arr addObject:@(arc4random()%50+80)];
		}
		_heightArr = [arr copy];
	}
	return _heightArr;
}
最近的文章

iOS 持续集成之 Gitlab-Ci + FastLane

Gitlab-Ci配置XcodeXcode唯一需要配置的就是要将你运行的scheme设置成Shared。 打开Xcode项目 选择Product > Scheme > Manage Schemes 将对应的scheme勾选上Shared安装 配置 GitLab Runner下载runner到本地sudo curl --output /usr/local/bin/gitlab-ci-multi-runner https://gitlab-ci-multi-runner-do...…

继续阅读
更早的文章

nginx 配置pathInfo

前言毕业设计买的服务器,选用nginx作为服务器,用的 ThinkPHP 作为开发框架,但是nginx默认不支持pathInfo路由格式(apache下是默认支持的).网上查了很多资料,但其中是不完整的,不能正确处理pathInfo.首先,修改文件/etc/nginx/fastcgi_params修改 SCRIPT_FILENAME 并添加 PATH_INFO 参数,如下:fastcgi_param QUERY_STRING $query_string;fastc...…

继续阅读