【IOS开发】collectionView 瀑布流实现

一、效果展示

二、思路分析

  1> 布局的基本流程

  当设置好collectionView的布局方式之后(UICollectionViewFlowLayout),当系统开始布局的时候,会调用 prepareLayout 来布局  

- (void)prepareLayout;

  与此同时,collectionViewCell 的每个控件的布局属性都会调用 以下方法来设置(可以重写方法来修改每个cell 的数值)

1 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect

  2> 每列 的高度计算方式

    1.计算所有的cell 的高度,然后平均下来,得到itemSize 然后计算每列的高度-----> 该方法不够精确,而且极端情况下会相差太大

    2.每次计算cell 的时候,找出高度最低的那一列,优先添加到该列,然后依次计算------> 该方法误差较小

  Tip: 在collectionView中,contentSize 就是一个摆设,不能根据这个来计算 collectionView 的大小,系统会自动的根据 itemSize 来计算

三、核心代码实现

  

 1 //
 2 //  WaterFall.h
 3 //  瀑布流
 4 //
 5 //  Created by gxiangzi on 15/9/16.
 6 //  Copyright © 2015年 hqu. All rights reserved.
 7 //
 8
 9 #import <UIKit/UIKit.h>
10
11 @interface WaterFall : UICollectionViewFlowLayout
12
13 // 计算列数
14 @property (assign, nonatomic) NSInteger columCount;
15 // 所有的模型数组
16 @property (strong, nonatomic) NSArray * dataList;
17
18 @end
  1 //
  2 //  WaterFall.m
  3 //  瀑布流
  4 //
  5 //  Created by gxiangzi on 15/9/16.
  6 //  Copyright © 2015年 hqu. All rights reserved.
  7 //
  8
  9 /**
 10
 11  // 获得高度的办法
 12     1. 计算总的高度,然后计算每个高度,最后设置itemsize 来计算
 13     2. 找出最高的列,然后根据最高的列来计算
 14  注意:collectionView 的contentView 是一个摆设,没有实际效果,需要根据 itemSize 来计算
 15
 16  */
 17
 18 #import "WaterFall.h"
 19 #import "Shop.h"
 20
 21 @interface WaterFall ()
 22
 23 @property (nonatomic,strong) NSMutableArray * itemsAttribute;
 24
 25 @end
 26
 27 @implementation WaterFall
 28
 29 -(void)prepareLayout
 30 {
 31     [super prepareLayout];
 32
 33 //    self.sectionFootersPinToVisibleBounds = YES;
 34
 35     // 计算每列的宽度
 36     CGFloat contentWidth = self.collectionView.bounds.size.width - self.sectionInset.left - self.sectionInset.right;
 37         CGFloat colWidth = (contentWidth - (self.columCount - 1) * self.minimumInteritemSpacing) / self.columCount;
 38     self.minimumInteritemSpacing = 10;
 39     self.minimumLineSpacing = 10;
 40
 41     [self attribute:colWidth];
 42 }
 43
 44 - (void) attribute:(CGFloat) colWidth
 45 {
 46     NSInteger colCount[self.columCount];
 47     CGFloat colHeight[self.columCount];
 48
 49     for (int i=0; i<self.columCount; ++i)
 50     {
 51         colHeight[i] = 0;
 52         colCount[i] = 0;
 53     }
 54
 55
 56     // 定义总item高
 57     CGFloat totoalItemHeight = 0;
 58
 59     // 定义一个可变数组,来存储 素有的属性值
 60     NSMutableArray * arrayM = [NSMutableArray arrayWithCapacity:self.dataList.count];
 61
 62     // 计数
 63     NSInteger index = 0;
 64
 65     // 遍历数组,计算相关的属性
 66     for (Shop * shop  in self.dataList)
 67     {
 68
 69         // 1> 建立布局属性
 70         NSIndexPath * indexPath = [NSIndexPath indexPathForRow:index inSection:0];
 71         index ++;
 72         UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
 73
 74         // 2.计算当前的列数
 75         // 计算是第几列
 76         NSInteger col = [self shortestCol:colHeight];
 77         // 计算每一列的个数
 78         colCount[col]++;
 79
 80         // 3.计算frame
 81         CGFloat w = shop.w;
 82         CGFloat h = shop.h * colWidth / w;
 83         CGFloat x = self.sectionInset.left + (colWidth + self.minimumInteritemSpacing) * col;
 84         CGFloat y = colHeight[col] + self.minimumLineSpacing;
 85         // 累加,计算同一列下一个元素的高度
 86         colHeight[col] += (h + self.minimumLineSpacing);
 87
 88         attr.frame = CGRectMake(x, y, colWidth, h);
 89
 90         // 4.计算总的高度
 91         totoalItemHeight += h;
 92
 93         // 5.添加到 itemsAttribute
 94         [arrayM addObject:attr];
 95     }
 96
 97     // 计算出最高的那一列
 98     NSInteger highestCol = [self highestColL:colHeight];
 99     // 设置 itemSize,使用总高度的平均值
100     self.itemSize = CGSizeMake(colWidth, (colHeight[highestCol]- colCount[highestCol] * self.minimumInteritemSpacing) / colCount[highestCol]);
101
102     // 添加页脚属性
103
104     UICollectionViewLayoutAttributes * footer = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter withIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
105     footer.frame = CGRectMake(0, colHeight[highestCol], self.collectionView.bounds.size.width, 50);
106
107     [arrayM addObject:footer];
108
109     self.itemsAttribute = arrayM;
110 }
111
112
113 /// 返回所有 cell 的属性数组
114 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
115 {
116     return self.itemsAttribute;
117 }
118
119 /// 获得最少的那一列
120 ///
121 /// @param colHeight 列高数组
122 ///
123 /// @return 最少的列号
124 - (NSInteger) shortestCol:(CGFloat *)colHeight {
125     CGFloat min = MAXFLOAT;
126     CGFloat col = 0;
127
128     for (int i=0; i<self.columCount; ++i)
129     {
130         if (colHeight[i] <  min) {
131             min = colHeight[i];
132             col = i;
133         }
134     }
135     return col;
136 }
137
138 /// 获得最高的那一列
139 ///
140 /// @param colHeight 列高数组
141 ///
142 /// @return 最高的列号
143 - (NSInteger) highestColL:(CGFloat *)colHeight {
144
145     CGFloat max = 0;
146     CGFloat col = 0;
147
148     for (int i=0; i<self.columCount; ++i)
149     {
150         if(colHeight[i] > max)
151         {
152             max = colHeight[i];
153             col = i;
154         }
155     }
156
157     return col;
158 }
159
160
161 #pragma mark - 懒加载 属性数组
162 - (NSMutableArray *)itemsAttribute
163 {
164     if (_itemsAttribute == nil)
165     {
166         _itemsAttribute = [NSMutableArray array];
167     }
168     return _itemsAttribute;
169 }
170
171 @end
时间: 2024-10-10 09:13:51

【IOS开发】collectionView 瀑布流实现的相关文章

iOS之简单瀑布流的实现

iOS之简单瀑布流的实现 前言 超简单的瀑布流实现,这里说一下笔者的思路,详细代码在这里. 实现思路 collectionView能实现各中吊炸天的布局,其精髓就在于UICollectionViewLayout,因此我们要自定义一个layout来继承系统的UICollectionViewLayout,所有工作都在这个类中进行. 1.定义所需属性 瀑布流的思路就是,从上往下,那一列最短,就把下一个item放在哪一列,因此我们需要定义一个字典来记录每一列的最大y值 每一个item都有一个attrib

iOS tableview(瀑布流) 滑动的时候卡顿解决

写的一个程序中用到了瀑布流的展现方式,但是发现当图片数量太大的时候,在iPhone4上会不流畅,这点很不爽. 写代码之初是做了一些优化的,比如cell重用,异步加载,但是还是很卡. 终于后来发现了症结所在,那就是,如果滑动太快,可能同时就发出了比如10个图片请求.这些请求虽然都在后台运行,但是它们可能在同一个时间点返回UI线程.这个时候如果加载图片到UIImageView太频繁,就会造成UI卡得严重.(虽然在new iPad和iPhone4s上看不出来) 在找到这个问题的同时,也发现perfor

iOS开发 - WaterflowLayout 瀑布流布局

Model Data @interface Shop : NSObject @property (nonatomic, assign) CGFloat w; @property (nonatomic, assign) CGFloat h; @property (nonatomic, copy) NSString *img; @property (nonatomic, copy) NSString *price; @end define cell @class Shop; @interface S

iOS开发 - AVPlayer实现流音频边播边存

边播边下有三套左右实现思路,本文使用AVPlayer + AVURLAsset实现. 概述 1. AVPlayer简介 AVPlayer存在于AVFoundation中,可以播放视频和音频,可以理解为一个随身听 AVPlayer的关联类: AVAsset:一个抽象类,不能直接使用,代表一个要播放的资源.可以理解为一个磁带子类AVURLAsset是根据URL生成的包含媒体信息的资源对象.我们就是要通过这个类的代理实现音频的边播边下的 AVPlayerItem:可以理解为一个装在磁带盒子里的磁带 2

iOS中的瀑布流(RootCollectionViewControlle)

用了三个第三方 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization af

iOS UITabView简写瀑布流

代码demo 一.tabViewCell,通过image的比例高算出cell 的高度 #import "TableViewCell.h" @implementation TableViewCell { UIImageView *imageView; } - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithSt

UI20- CollectionView瀑布流

?CollectionView: 瀑布流: 1.cell 大小改变的时重写layOutSubviews; 2.layOut的属性: 3.瀑布流 (1)创建model (2)重写layout 1)在声明里,生成代理,必须的属性设置, 2)延展的属性和方法: 3)对定义的2个数组进行懒加载,实现延展的方法: 4)准备阶段每个item的大小, 5)根据求出的最长列的高度,来设置collection的view的高度. (3) 自定义cell,重写layoutsubView 方法,当大小改变时候,cell

iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流

上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewController(二) --详解CollectionView各种回调>.UICollectionView之所以强大,是因为其具有自定义功能,这一自定义就不得了啦,自由度非常大,定制的高,所以功能也是灰常强大的.本篇博客就不使用自带的流式布局了,我们要自定义一个瀑布流.自定义的瀑布流可以配置其参数: 每个Cell的边距

iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流

在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,Cell的最大以及最小高度是在我们的布局文件中是写死的,换句话说也就是不可配置的.为了循序渐进,由浅入深呢,上篇博客暂且那么写.不过那样写太过死板,本来使用起来比较灵活的自定义布局,如果把其配置参数给写死了,就相当于在笼中的猛兽,再厉害不也白扯蛮. 在今天这篇博客中我们要接着上篇博客中的Demo,使其自定义布局