最近学习到了瀑布流的实现方法,瀑布流的实现方式有多种,这里应用collectionView来重写其UICollectionViewLayout进行布局是最为简单方便的。但再用其布局之前必须了解其布局原理。  

在这里笔者挑出其中较为重要的几个方法来进行讲解。

1.- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

当collectionView视图位置有新改变(发生移动)时调用,其若返回YES则重新布局

2.- (void)prepareLayout

准备好布局时调用。此时collectionView所有属性都已确定。读者在这里可以将collectionView当做画布,有了画布后,我们便可以在其上面画出每个item

3.- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

返回collectionView视图中所有视图的属性(UICollectionViewLayoutAttributes)数组

4.- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

返回indexPath对应item的属性

5.- (CGSize)collectionViewContentSize

设置collectionView的可显示范围

这些方法中最重要的便是3,4方法,

在3方法中返回所有视图属性数组,并根据这些属性进行布局,

而4方法则返回每个item的属性,我们则在这里设置每个item的属性(主要是frame),就可以让collectionView按照我们的意愿进行布局了!

(在这里我们不需要用到1方法,若item属性根据滑动改变,此时就需要随时进行布局改变)  

瀑布流的实现示意图如下

由图示意可看出除开最开始3个item,后面的item都是存放3列中的最短列上面,因此我们只需要计算出每个item的frame,并摆放的话那我们的瀑布流自然就成功了。

.h文件中

1 typedef CGFloat(^HeightBlock)(NSIndexPath *indexPath , CGFloat width);

2 @interface BQWaterLayout : UICollectionViewLayout

3 /** 列数 */

4 @property (nonatomic, assign) NSInteger lineNumber;

5 /** 行间距 */

6 @property (nonatomic, assign) CGFloat rowSpacing;

7 /** 列间距 */

8 @property (nonatomic, assign) CGFloat lineSpacing;

9 /** 内边距 */

10 @property (nonatomic, assign) UIEdgeInsets sectionInset;

11 /**

12 * 计算各个item高度方法 必须实现

13 *

14 * @param block 设计计算item高度的block

15 */

16 - (void)computeIndexCellHeightWithWidthBlock:(CGFloat(^)(NSIndexPath *indexPath , CGFloat width))block;

17 @end

为了方便修改瀑布流的布局我们需要设置排列布局的各个接口,因为瀑布流中只能通过列数计算出item的宽,因此需要使用computeIndexCellHeightWithWidthBlock来计算出每个item的高度(利用宽高比)!

.m文件中

代码中注释已经写的很明白了,无需多做解释,此处写法只能实现item的布局,不能添加headview或footview!

1 @interface BQWaterLayout()

2 /** 存放每列高度字典*/

3 @property (nonatomic, strong) NSMutableDictionary *dicOfheight;

4 /** 存放所有item的attrubutes属性*/

5 @property (nonatomic, strong) NSMutableArray *array;

6 /** 计算每个item高度的block,必须实现*/

7 @property (nonatomic, copy) HeightBlock block;

8 @end

9

10 @implementation BQWaterLayout

11 - (instancetype)init

12 {

13 self = [super init];

14 if (self) {

15 //对默认属性进行设置

16 /**

17 默认行数 3行

18 默认行间距 10.0f

19 默认列间距 10.0f

20 默认内边距 top:10 left:10 bottom:10 right:10

21 */

22 self.lineNumber = 3;

23 self.rowSpacing = 10.0f;

24 self.lineSpacing = 10.0f;

25 self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);

26 _dicOfheight = [NSMutableDictionary dictionary];

27 _array = [NSMutableArray array];

28 }

29 return self;

30 }

31

32 /**

33 * 准备好布局时调用

34 */

35 - (void)prepareLayout{

36 [super prepareLayout];

37 NSInteger count = [self.collectionView numberOfItemsInSection:0];

38 //初始化好每列的高度

39 for (NSInteger i = 0; i < self.lineNumber ; i++) {

40 [_dicOfheight setObject:@(self.sectionInset.top) forKey:[NSString stringWithFormat:@"%ld",i]];

41 }

42 //得到每个item的属性值进行存储

43 for (NSInteger i = 0 ; i < count; i ++) {

44 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

45 [_array addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];

46 }

47 }

48 /**

49 * 设置可滚动区域范围

50 */

51 - (CGSize)collectionViewContentSize{

52 NSLog(@"collectionViewContentSize");

53 __block NSString *maxHeightline = @"0";

54 [_dicOfheight enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *obj, BOOL *stop) {

55 if ([_dicOfheight[maxHeightline] floatValue] < [obj floatValue] ) {

56 maxHeightline = key;

57 }

58 }];

59 return CGSizeMake(self.collectionView.bounds.size.width, [_dicOfheight[maxHeightline] floatValue] + self.sectionInset.bottom);

60 }

61 /**

62 * 计算indexPath下item的属性的方法

63 *

64 * @return item的属性

65 */

66 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{

67 //通过indexPath创建一个item属性attr

68 UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

69 //计算item宽

70 CGFloat itemW = (self.collectionView.bounds.size.width - (self.sectionInset.left + self.sectionInset.right) - (self.lineNumber - 1) * self.lineSpacing) / self.lineNumber;

71 CGFloat itemH;

72 //计算item高

73 if (self.block != nil) {

74 itemH = self.block(indexPath, itemW);

75 }else{

76 NSAssert(itemH != 0,@"Please implement computeIndexCellHeightWithWidthBlock Method");

77 }

78 //计算item的frame

79 CGRect frame;

80 frame.size = CGSizeMake(itemW, itemH);

81 //循环遍历找出高度最短行

82 __block NSString *lineMinHeight = @"0";

83 [_dicOfheight enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *obj, BOOL *stop) {

84 if ([_dicOfheight[lineMinHeight] floatValue] > [obj floatValue]) {

85 lineMinHeight = key;

86 }

87 }];

88 int line = [lineMinHeight intValue];

89 //找出最短行后,计算item位置

90 frame.origin = CGPointMake(self.sectionInset.left + line * (itemW + self.lineSpacing), [_dicOfheight[lineMinHeight] floatValue]);

91 _dicOfheight[lineMinHeight] = @(frame.size.height + self.rowSpacing + [_dicOfheight[lineMinHeight] floatValue]);

92 attr.frame = frame;

93

94 return attr;

95 }

96 /**

97 * 返回视图框内item的属性,可以直接返回所有item属性

98 */

99 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{

100 return _array;

101 }

102 /**

103 * 设置计算高度block方法

104 *

105 * @param block 计算item高度的block

106 */

107 - (void)computeIndexCellHeightWithWidthBlock:(CGFloat (^)(NSIndexPath *, CGFloat))block{

108 if (self.block != block) {

109 self.block = block;

110 }

111 }

112 @end

至此一个简单的collectionViewLayout瀑布流布局便设置完成,只需要在自己代码中使用此布局便可以得到一个瀑布流了!

笔者本来开始还担心如果item过多,那么设置的属性就会过多,比如数组内存放一千或一万个item的属性,后来经过笔者测试后发现,系统应该每次都是事先计算好了所有item的属性(通过tableView计算每行高度的代理方法来思考),因此直接初始化好所有item的属性做法应该不会有太大弊端!

collectionView布局原理及瀑布流布局方式--备用的更多相关文章

  1. collectionView布局原理及瀑布流布局方式

    一直以来都想研究瀑布流的具体实现方法(起因是因为一则男女程序员应聘的笑话,做程序的朋友应该都知道).最近学习到了瀑布流的实现方法,瀑布流的实现方式有多种,这里应用collectionView来重写其U ...

  2. 【CSS】瀑布流布局的两种方式:传统多列浮动和绝对定位布局

    传统多列浮动 各列固定宽度,并且左浮动: 一列中的数据块为一组,列中的每个数据块依次排列即可: 更多数据加载时,需要分别插入到不同的列上: 优点: (1)布局简单,应该说没啥特别的难点: (2)不用明 ...

  3. 关于瀑布流的布局原理分析(纯CSS瀑布流与JS瀑布流)

    瀑布流 又称瀑布流式布局,是比较流行的一种网站页面布局方式.即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置. 为什么使用瀑 ...

  4. Xamarin自定义布局系列——瀑布流布局

    Xamarin.Forms以Xamarin.Android和Xamarin.iOS等为基础,自己实现了一整套比较完整的UI框架,包含了绝大多数常用的控件,如下图 虽然XF(Xamarin.Forms简 ...

  5. 瀑布流布局使用详解——JQuery插件Isotope(动态实现子项目筛选)

    瀑布流布局,听起来听牛逼的样子,其实就是简单的子元素筛选功能.不过这一功能在网站页面布局当中还是很常用的,特别是在电商网站中 经常会有点一个钮筛选,然后页面的子元素刷的以下变了样.接下来,我们先简单介 ...

  6. Django 项目补充知识(JSONP,前端瀑布流布局,组合搜索,多级评论)

    一.JSONP 1浏览器同源策略 通过Ajax,如果在当前域名去访问其他域名时,浏览器会出现同源策略,从而阻止请求的返回 由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一 ...

  7. jquery实现简单瀑布流布局

    jquery实现简单瀑布流布局 是开头都会说的原理 瀑布流布局有两种,一种是固定列,一种是非固定列.在此主要记述第一种的实现. 固定列的特征是:无论页面如何缩放,每行的总列数都一致. 一行4列的瀑布流 ...

  8. 通过Measure & Arrange实现UWP瀑布流布局

    简介 在以XAML为主的控件布局体系中,有用于完成布局的核心步骤,分别是measure和arrange.继承体系中由UIElement类提供Measure和Arrange方法,并由其子类Framewo ...

  9. 也来谈谈wap端瀑布流布局

    Definition 瀑布流布局,在视觉上表现为参差不齐的多栏布局,随着页面滚动条向下滚动,新数据不断被加载进来. 瀑布流对于图片的展现,是高效而具有吸引力的,用户一眼扫过的快速阅读模式可以在短时间内 ...

随机推荐

  1. Convert Date between LocalDateTime

    http://blog.progs.be/542/date-to-java-time Java8 has new date and time classes to “replace” the old ...

  2. Android 自学之列表选择框Spinner

    列表选择框(Spinner)与Swing编程里面的Spinner不同,这里的Spinner其实就是一个列表选项框. Spinner是ViewGroup的间接子类,因此他也可作为容器使用. Spinne ...

  3. 条件阻塞Condition的应用

    Condition的功能类似在传统线程技术中的Object.wait和Object.notity的功能.   例子:生产者与消费者 import java.util.Random; import ja ...

  4. 为Debain &&Centos安装dig

    Debain&Ubuntu sudo apt-get install dnsutils Fdeoar&Centos yum install bind-utils

  5. highcharts 去掉右下角链接

    去掉右下角的highcharts.com链接需要加入以下代码: credits: { enabled:false }, 如果不设置,那么默认为显示.

  6. 跨域方法之CORS

    跨域的方法非常之多,如果想了解其中CORS,不要浪费时间,看下面三个就够了 了解CORS   https://developer.mozilla.org/en-US/docs/Web/HTTP/Acc ...

  7. h2database源码浅析:SQL语句的执行

    最近想好好了解一下数据库的原理,下载了h2database的源码,准备好好看看.此过程的一些想法,暂且记下来,权当做读码笔记吧! 为了调试准备的测试用例: @Test public void test ...

  8. ASP长文章分页的两个方法,函数

    '按标识手动分页 function manualPage(str) pages=request.QueryString("page") contentstr=split(str,& ...

  9. C#数据等待

    1 public bool WaitData() 2 { 3 bool states = false; 4 try 5 { 6 DateTime Get_Time = DateTime.Now; 7 ...

  10. 我踩过的Alwayson的坑!(上集)

    最近被sql server Alwayson高可用组和读写分离,弄得神魂颠倒,身心俱疲.遇到了下面一些问题,提醒自己也给后来人做些记录. EntityFramework支不支持Alwayson? 起因 ...