首页 > 其他分享 >一个简单的瀑布流布局的实现

一个简单的瀑布流布局的实现

时间:2022-12-08 14:05:01浏览次数:64  
标签:collectionView self 布局 sectionInset item 瀑布 简单 attributes maxYDic


(实现了瀑布流功能,但是不能添加头部和底部视图,如项目中有添加头部或底部视图的需求,请自行修改)

实现思路

collectionView能实现各中吊炸天的布局,其精髓就在于UICollectionViewLayout,因此我们要自定义一个layout来继承系统的UICollectionViewLayout,所有工作都在这个类中进行。

1.定义所需属性

瀑布流的思路就是,从上往下,那一列最短,就把下一个item放在哪一列,因此我们需要定义一个字典来记录每一列的最大y值

每一个item都有一个attributes,因此定义一个数组来保存每一个item的attributes。

我们还必须知道有多少列以及列间距、行间距、section到collectionView的边距。

一个简单的瀑布流布局的实现_继承



//总列数
@property (nonatomic, assign) NSInteger columnCount;
//列间距
@property (nonatomic, assign) NSInteger columnSpacing;
//行间距
@property (nonatomic, assign) NSInteger rowSpacing;
//section到collectionView的边距
@property (nonatomic, assign) UIEdgeInsets sectionInset;
//保存每一列最大y值的数组
@property (nonatomic, strong) NSMutableDictionary *maxYDic;
//保存每一个item的attributes的数组
@property (nonatomic, strong) NSMutableArray *attributesArray;



2.重写系统方法

我们一共需要重写4个方法



1)- (void)prepareLayout
2)- (CGSize)collectionViewContentSize
3)- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
4)- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect



- (void)prepareLayout 方法

布局前的一些准备工作都在这里进行,初始化字典,有几列就有几个键值对,key为第几列,value为列的最大y值,初始值为上内边距:



for (int i = 0; i < self.columnCount; i++) {
self.maxYDic[@(i)] = @(self.sectionInset.top);
}



创建每个item的attributes,并存入数组:



//根据collectionView获取总共有多少个item
NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];
//为每一个item创建一个attributes并存入数组
for (int i = 0; i < itemCount; i++) {
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[self.attributesArray addObject:attributes];
}



- (CGSize)collectionViewContentSize 方法

用来计算collectionView的contentSize

一般瀑布流只能垂直滚动,不能水平滚动,因此contentSize.width = 0,我们只需要计算contentSize.height即可

从字典中找出最长列的最大y值,再加上下面的内边距,即为contentSize.height



- (CGSize)collectionViewContentSize {
//假设第0列是最长的那列
__block NSNumber *maxIndex = @0;
//遍历字典,找出最长的那一列
[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {
//如果maxColumn列的最大y值小于obj,则让maxColumn等于obj所属的列
if ([self.maxYDic[maxIndex] floatValue] < obj.floatValue) {
maxIndex = key;
}
}];
//collectionView的contentSize.height就等于最长列的最大y值+下内边距
return CGSizeMake(0, [self.maxYDic[maxIndex] floatValue] + self.sectionInset.bottom);
}



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

该方法则用来设置每个item的attributes,在这里,我们只需要简单的设置每个item的attributes.frame即可

首先我们必须得知collectionView的尺寸,然后我们根据collectionView的宽度,以及列数、各个间距来计算每个item的宽度

item的宽度 = (collectionView的宽度 - 内边距及列边距) / 列数

一个简单的瀑布流布局的实现_继承_02



CGFloat collectionViewWidth = self.collectionView.frame.size.width;
//self.sectionInset.left:左边距 self.sectionInset.right:右边距
//(self.columnCount - 1) * columnSpacing:一行中所有的列边距
CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount;



接下来计算item的坐标,要想计算坐标,那就必须知道最短的那一列,先遍历字典,找出最短列是哪一列(minColumn)以及其最大y值。

item的y值就等于最短列的最大y值再加上行间距,x值就等于左边距 + (item宽度 + 列间距) * minColumn

一个简单的瀑布流布局的实现_布局_03



//找出最短的那一列
__block NSNumber *minIndex = @0;
[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {
if ([self.maxYDic[minIndex] floatValue] > obj.floatValue) {
minIndex = key;
}
}];
//根据最短列的列数计算item的x值
CGFloat itemX = self.sectionInset.left + (self.columnSpacing + itemWidth) * minIndex.integerValue;
//item的y值 = 最短列的最大y值 + 行间距
CGFloat itemY = [self.maxYDic[minIndex] floatValue] + self.rowSpacing;



接下来便是item的高度,我们应该根据图片的原始尺寸以及计算出来的宽度,等比例缩放来计算高度,但是在layout类中,我们是拿不到图片的,因此我们可以定义一个block属性,或者代理,让外界来计算并返回给我们,我们需要将item的宽度以及indexPath传递给外界:



@property (nonatomic, strong) CGFloat(^itemHeightBlock)(CGFloat itemHeight,NSIndexPath *indexPath);


根据返回值来设置item的高度:



if (self.itemHeightBlock) itemHeight = self.itemHeightBlock(itemWidth, indexPath);



最后设置attributes的frame并更新字典:



//设置attributes的frame
attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);
//更新字典中的最短列的最大y值
self.maxYDic[minIndex] = @(CGRectGetMaxY(attributes.frame));



- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 方法

该方法用来返回rect范围内,item的attributes

直接返回attributesArray即可



- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
return self.attributesArray;
}



使用

布局类写完了,接下来就可以直接使用了



//创建布局对象
XRWaterfallLayout *waterfall = [[XRWaterfallLayout alloc] init];
//设置相关属性
waterfall.columnCount = 3;//共多少列
waterfall.columnSpacing = 10;//列间距
waterfall.rowSpacing = 10;//行间距
waterfall.sectionInset = UIEdgeInsetsMake(10, 10 , 10, 10);//内边距
[waterfall setItemHeightBlock:^CGFloat(CGFloat itemWidth, NSIndexPath *indexPath) {
//根据图片的原始尺寸,及显示宽度,等比例缩放来计算显示高度
XRImage *image = self.images[indexPath.item];
return image.imageH / image.imageW * itemWidth;
}];
collectionView.collectionViewLayout = waterfall;
......
......



具体代码下载:​​https://github.com/codingZero/XRWaterfallLayout​​,具有使用说明

标签:collectionView,self,布局,sectionInset,item,瀑布,简单,attributes,maxYDic
From: https://blog.51cto.com/u_15894905/5921073

相关文章

  • 创建简单图元-示例代码
    #include"AcDrawManage.h"#include"AcDbPlotSettings.h"voidAppBowen::create2dDraw(){ //draw2d AfxMessageBox("draw2d"); //获取当前活动的Draw AcDr......
  • php一个简单的测试工具simpletest
    phpunit是很好的单元测试工具,而本文介绍一款更轻量级的单元测试工具,开源的,simpletest,1下载:​​​  http://sourceforge.net/projects/simp......
  • CSS Flex布局
    Flex布局单行多元素,可以考虑Flex布局,好处是居中、对齐比较好控制容器布局,决定使用Flex,横向(rowrow-reverse)还是纵向排列(columncolumn-reverse),是否折行(flex-wrap,......
  • 一、TestDriven.NET简单介绍
    前言一个典型的软件项目中最为重要的两种测试类型,即程序员和用户的测试,称为“单元测试”和“验收测试”。在开发任何种类的企业或大型应用时都不容忽视,如果没有合适的工具......
  • 《悟透javascript》学习笔记:二、回归简单
    引言 要理解JavaScript,你得首先放下对象和类的概念,回到数据和代码的本原。前面说过,编程世界只有数据和代码两种基本元素,而这两种元素又有着纠缠不清的关系。JavaScript就......
  • element-ui 表单组件的简单封装
    背景在管理系统中我们需要经常使用表单组件来收集用户的一些数据,如果按照官网的示例一个个表单项去填写不仅代码会变得很长而且麻烦,所以我们有必要去对组件进行再次的封装......
  • 《出的题不能太简单,不然会被嘲讽没水准》 回复
    《出的题不能太简单,不然会被嘲讽没水准》       https://tieba.baidu.com/p/8175420636      6楼楼主的题最后都要变成二元一次不定方程来解,感......
  • 内网安全 - 简单域环境搭建
    内网安全-简单域环境搭建使用WindowsServer2012R2,Windows7,WindowsXP配置域控环境。虚拟机的获取和安装不再叙述,安装时网络选择桥接模式。域基础知识这里......
  • xlsx合并单元格简单介绍
    在使用xlsx导出excel表格的时候,有时候我们需要将某些表格进行合并,该如何做呢,代码如下:importXLSXfrom'xlsx';//...//xlsxData是Excel的内容constworkSheet=X......
  • 010.绘制后台首页UI布局
    1.index.html<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>慕课网办公OA系统</title><!--引入样式--><linkrel="style......