承继UICollectionViewLayout自定义布局,瀑布流飞快完

那八个都以用UICollectionView落成的,解决这八个demo,就可以驾驭UICollectionView.

现行反革命随处可遇,种种App首页选拔瀑布流浮现的功力,瀑布流它是一种自定义的布局形式,比如系统的FlowOut流水布局样式,直接上代码

原稿地址:http://www.jianshu.com/p/040c824736cd

切实达成如下:

可是图片轮播demo github地址

自定义WaterflowLayout类继承UICollectionViewLayout

UICollectionView落成瀑布流

LYFWaterflowLayout.h

#import <UIKit/UIKit.h>

@class LYFWaterflowLayout;

@protocol LYFWaterflowLayoutDelegate@required

/** cell高度  */

- (CGFloat)waterflowLayout:(LYFWaterflowLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth;

@optional

/** 行数或列数(默认3  */

- (CGFloat)columnCountInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout;

/** 列间距 */

- (CGFloat)columnMarginInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout;

/** 行间距 */

- (CGFloat)rowMarginInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout;

/** 内边距 */

- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout;

@end

@interface LYFWaterflowLayout : UICollectionViewLayout

/** 代理 */

@property (nonatomic, weak) iddelegate;

@end

瀑布流 demo github地址

完成以下4个章程

在iOS中能够达成瀑布流的脚下已知的有2种方案:

LYFWaterflowLayout.m

/** 暗中认可的列数 */

static const NSInteger LYFDefaultColumnCount = 3;

/** 每一列之间的间隔 */

static const CGFloat LYFDefaultColumnMargin = 10;

/** 每一行之间的区间 */

static const CGFloat LYFDefaultRowMargin = 10;

/** 边缘间距 */

static const UIEdgeInsets LYFDefaultEdgeInsets = {10, 10, 10, 10};

@interface LYFWaterflowLayout()

/** 存放全体cell的布局属性 */

@property (nonatomic, strong) NSMutableArray *attrsArray;

/** 存放全数列的此时此刻中度 */

@property (nonatomic, strong) NSMutableArray *columnHeights;

/** 内容的莫斯科大学 */

@property (nonatomic, assign) CGFloat contentHeight;

- (CGFloat)rowMargin;

- (CGFloat)columnMargin;

- (NSInteger)columnCount;

- (UIEdgeInsets)edgeInsets;

@end

@implementation LYFWaterflowLayout

#pragma mark - 常见数据管理

- (CGFloat)rowMargin

{

if ([self.delegate respondsToSelector:@selector(rowMarginInWaterflowLayout:)]) {

return [self.delegate rowMarginInWaterflowLayout:self];

} else {

return LYFDefaultRowMargin;

}

}

- (CGFloat)columnMargin

{

if ([self.delegate respondsToSelector:@selector(columnMarginInWaterflowLayout:)]) {

return [self.delegate columnMarginInWaterflowLayout:self];

} else {

return LYFDefaultColumnMargin;

}

}

- (NSInteger)columnCount

{

if ([self.delegate respondsToSelector:@selector(columnCountInWaterflowLayout:)]) {

return [self.delegate columnCountInWaterflowLayout:self];

} else {

return LYFDefaultColumnCount;

}

}

- (UIEdgeInsets)edgeInsets

{

if ([self.delegate respondsToSelector:@selector(edgeInsetsInWaterflowLayout:)]) {

return [self.delegate edgeInsetsInWaterflowLayout:self];

} else {

return LYFDefaultEdgeInsets;

}

}

#pragma mark - 懒加载

- (NSMutableArray *)columnHeights

{

if (!_columnHeights) {

_columnHeights = [NSMutableArray array];

}

return _columnHeights;

}

- (NSMutableArray *)attrsArray

{

if (!_attrsArray) {

_attrsArray = [NSMutableArray array];

}

return _attrsArray;

}

/**

* 初始化

*/

- (void)prepareLayout

{

[super prepareLayout];

self.contentHeight = 0;

// 清除在此以前划算的具有中度

[self.columnHeights removeAllObjects];

for (NSInteger i = 0; i < self.columnCount; i ) {

[self.columnHeights addObject:@(self.edgeInsets.top)];

}

// 清除在此以前全数的布局属性

[self.attrsArray removeAllObjects];

// 开首制造每七个cell对应的布局属性

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

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

// 制造地方

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

// 获取indexPath地方cell对应的布局属性

UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];

[self.attrsArray addObject:attrs];

}

}

/**

* 决定cell的排布

*/

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

{

return self.attrsArray;

}

/**

* 重回index帕特h地方cell对应的布局属性

*/

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

{

// 创制布局属性

UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

// collectionView的宽度

CGFloat collectionViewW = self.collectionView.frame.size.width;

// 设置布局属性的frame

CGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;

CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:w];

// 搜索中度最短的那一列

NSInteger destColumn = 0;

CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];

for (NSInteger i = 1; i < self.columnCount; i ) {

// 猎取第i列的可观

CGFloat columnHeight = [self.columnHeights[i] doubleValue];

if (minColumnHeight > columnHeight) {

minColumnHeight = columnHeight;

destColumn = i;

}

}

CGFloat x = self.edgeInsets.left destColumn * (w self.columnMargin);

CGFloat y = minColumnHeight;

if (y != self.edgeInsets.top) {

y = self.rowMargin;

}

attrs.frame = CGRectMake(x, y, w, h);

// 更新最短那列的万丈

self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));

// 记录内容的莫斯中国科学技术大学学

CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];

if (self.contentHeight < columnHeight) {

self.contentHeight = columnHeight;

}

return attrs;

}

- (CGSize)collectionViewContentSize

{

return CGSizeMake(0, self.contentHeight self.edgeInsets.bottom);

}

功用图如下

@interface UICollectionWaterflowLayout : UICollectionViewLayout

选拔UIScrollView自个儿封装一套,这种方案是运用于iOS6事先的,因为iOS6才出来UICollectionView,可是未来这种方案已经有个别用了,还得要好包裹。而且本身包裹的特性不肯定有类别的投机。

现实应用如下:

LYFWaterflowLayout *layout = [[LYFWaterflowLayout alloc]init];

layout.delegate =self;

UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout]; 

  • 最为图片轮播

    图片 1极致轮播_.gif

  • 瀑布流

/**

选拔系统自带的UICollectionView,然后自定义layout,本人完结瀑布流效果

cell中度设置(必需贯彻的代办)

- (CGFloat)waterflowLayout:(LYFWaterflowLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth

{

return self.view.frame.size.height / 3;

}

图片 2瀑布流.gif

* 初始化

本文中大家介绍第三种完成方案

设置行数或列数(默认为3)

- (CGFloat)columnCountInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout

{

return 4;

}

落到实处图片Infiniti轮播的机要思路图如下

图片 3显示屏快照二〇一五-10-25 10.17.36.png

  • 一旦你要展现3张图片,完成Infiniti循环滚动,你成立两组6个collectionViewCell, 初始化时候滚动到第二组的率先个cell,达成那或多或少内需在UICollectionView初叶化时候在主队列增添滚动义务.

  • 安插职务在主线程上进行,若是主线程当前有职务,主队列临时不调治职责!所以等cell的数据源和代办方法施行实现后才实行那一个block里面包车型客车轮转职分.一般大家开拓中用到八线程有两点:1. 无比循环图片轮播器.2.异步裁剪图片,见小编的另一篇小说ImageView品质测验以及优化

     dispatch_async(dispatch_get_main_queue(), ^{ NSIndexPath *indexPath = [NSIndexPath indexPathForItem:_urls.count inSection:0]; // 滚动位置! [self scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO]; });
    
  • 在- scrollViewDidEndDecelerating:(UIScrollView *)scrollView {}scrollView那么些代理方法里面判别cell滚动的职位,假诺一骨碌到最终一组最后一张,则让总体滚动到第一组最终一张.假使滚动到第一组第一张,则滚动到终极一组第一张.

  • scrollViewDidEndDecelerating:(UIScrollView *)scrollView {// 1. 取妥贴前终止的页面NSInteger offset = scrollView.contentOffset.x / scrollView.bounds.size.width;// 2. 第0页,调转到,第1组的第0页// 最终一页,跳转到第0组的结尾一页if (offset == 0 || offset == ([self numberOfItemsInSection:0] - 1)) {// NSLog(@"%zd", offset);// 第 0 页if (offset == 0) {offset = _urls.count;} else {offset = _urls.count - 1;}// 重新调节contentOffsetscrollView.contentOffset = CGPointMake(offset * scrollView.bounds.size.width, 0);}}

系统调用滚动方法时候会卡顿,在numberOfItemsInSection里面进行如下代码管理

  • (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {//这里为了避防万一滚动到终极一页来回跳动导致的卡顿,多写点组数让平昔到不断最终一组,因为cell重用,所以不影响内部存款和储蓄器.return _urls.count * 100;}
  • 重视是自定义二个WaterFlowLayout : UICollectionViewLayout类,建叁个代理,调整器首先开首化WaterFlowLayout,何况遵守代理,重返cell的宽高.修改cell的UICollectionViewLayoutAttributes属性,使在布局时候每四个cell放到全部列高度最短那一列,这样的cell不是按梯次布局的.

import "WaterFlowLayout.h"/** 默许列数 /static const NSInteger DefaultColumnCount = 3;/* 每一列之间的距离 /static const NSInteger DefaultColumnMargin = 10;/* 每一行之间的区间 /static const NSInteger DefaultRowMargin = 10;/* 边缘间距 */static const UIEdgeInsets DefaultEdgeInsets = {0, 0, 0, 0};

@interface WaterFlowLayout ()/** 寄放全部cell的布局属性 /@property (nonatomic, strong) NSMutableArray attrsArray;/ 贮存全数列的方今中度 /@property (nonatomic, strong) NSMutableArraycolumnHeights;/ 内容的惊人 */@property (nonatomic, assign) CGFloat contentHeight;@end

@implementation WaterFlowLayout/**

  • 初始化*/
  • prepareLayout {[super prepareLayout];self.contentHeight = 0;//清除以前划算的富有中度[self.columnHeights removeAllObjects];//记录每一列的可观 一共3列for (NSInteger i = 0; i < DefaultColumnCount; i ) {[self.columnHeights addObject:@(DefaultEdgeInsets.top)];// NSLog(@"%f",self.edgeInsets.top);}//清除在此之前全部布局属性[self.attrsArray removeAllObjects];//开首创办每多少个cell对应发表局属性NSInteger count = [self.collectionView numberOfItemsInSection:0];for (NSInteger i = 0; i < count; i ) {//创制地点NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];//获取indexPath地方cell对应的布局属性UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];[self.attrsArray addObject:attrs];}}

/**

  • 调控cell的布局 prepareLayout后会调用一遍,上面方法调用完结修改cell属性后会再一次调用这一个主意*/
  • (NSArray *)layoutAttributesForElementsInRect:rect {return self.attrsArray;}

/**

  • 归来每三个职位cell对应的布局属性 修改 self.attrsArray里面cell的属性,那么些法子实践后再调用上三个艺术*/
  • (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {//创设布局属性UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];//collectionView的大幅度CGFloat collectionViewW = self.collectionView.frame.size.width;//设置布局属性的frameCGFloat w = (collectionViewW - DefaultEdgeInsets.left - Default艾德geInsets.right - (DefaultColumnCount - 1) * DefaultRowMargin) / DefaultColumnCount;CGFloat h = [self.delegate waterflowlayout:self heightForItemAtIndex:indexPath.item itemWidth:w];
//找出高度最短的那一列NSInteger destColumn = 0;//默认第一列最短CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];for (NSInteger i = 0; i < DefaultColumnCount; i  ) { //取得第i列的高度 CGFloat columnHeight = [self.columnHeights[i] doubleValue]; //minColumnHeight是最短那一列的高度,destColumn最短那一列 if (minColumnHeight > columnHeight) { minColumnHeight = columnHeight; destColumn = i; }}CGFloat x = DefaultEdgeInsets.left   destColumn * (w   DefaultColumnMargin);CGFloat y = minColumnHeight;if (y != DefaultEdgeInsets.top) { y  = DefaultRowMargin;}attrs.frame = CGRectMake(x, y, w, h);//更新最短那列的高度self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));//记录内容的高度CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];if (self.contentHeight < columnHeight) { self.contentHeight = columnHeight;}return attrs;

}

//全部的惊人

  • collectionViewContentSize {return CGSizeMake(0, self.contentHeight DefaultEdgeInsets.bottom);}

*/

第一我们须要自定义二个后续于UICollectionViewLayout的layout,然后供给重写多少个方法:

安装列间距(默以为10)

- (CGFloat)columnMarginInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout

{

return 20;

}

- (void)prepareLayout

(void)prepareLayout

安装行间距(默感到10)

- (CGFloat)rowMarginInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout

{

return 20;

}

{

(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

设置内边距(默认为10,10,10,10)

- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(LYFWaterflowLayout *)waterflowLayout

{

return UIEdgeInsetsMake(20, 20, 20, 20);

}

[super prepareLayout];

(UICollectionViewLayoutAttributes)layoutAttributesForItemAtIndexPath:(NSIndexPath)indexPath

self.contentHeight = 0;

(CGSize)collectionViewContentSize

// 清除以前划算的装有高度

率先个主意是做一些最初化的操作,那些艺术必需先调用一下父类的贯彻

[self.columnHeights removeAllObjects];

其次个格局重回的是多少个装着UICollectionViewLayoutAttributes的数组

for (NSInteger i = 0; i < self.columnCount; i ) {

其七个办法再次来到indexPath地点的UICollectionViewLayoutAttributes

[self.columnHeights addObject:@(self.edgeInsets.top)];

第多个主意是回去UICollectionView的可滚动范围

}

怎么落到实处瀑布流

// 清除以前全部的布局属性

首先大家供给知道有些瀑布流的排列,瀑布流是大小不法则的有的控件遍及在手提式有线电话机荧屏方面,然后确定有长度高的也可以有矮的(就好像人的身体高度一样,哈哈哈),当排满第一排的时候就能够往下一而再排,那么这些相应往哪个地方放呢,==答案正是把它内置第一排最短的十一分上面==,就那样类推,遵照这一个规律排列下去。

[self.attrsArray removeAllObjects];

接头了这点我们接下去就该写代码了

// 开端创制每八个cell对应的布局属性

先是我们创造三个数组二个装着cell的布局属性,另贰个装着重下cell的总高度

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

//c寄放全体cell的布局属性@property(nonatomic,strong)NSMutableArray*attrsArray;//寄放全体列的脚下高度@property(nonatomic,strong)NSMutableArray*columnHeights;/** 内容的莫斯中国科学技术大学学 */@property(nonatomic,assign)CGFloatcontentHeight;

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

- (void)prepareLayout{    [superprepareLayout];self.contentHeight =0;//清除从前总计的具备中度,因为刷新的时候回调用这一个点子[self.columnHeights removeAllObjects];for(NSIntegeri =0; i < DefaultColumnCpunt; i ) {        [self.columnHeights addObject:@(self.edgeInsets.top)];    }//把最先化的操作都放到这里[self.attrsArray removeAllObjects];//初叶创立每贰个cell对应的布局属性NSIntegercount = [self.collectionView numberOfItemsInSection:0];for(NSIntegeri =0; i < count; i ) {// 成立地方NSIndexPath*indexPath = [NSIndexPathindexPathForItem:i inSection:0];// 获得indexPath地方cell对应的布局属性UICollectionViewLayoutAttributes*attrs = [selflayoutAttributesForItemAtIndexPath:indexPath];        [self.attrsArray addObject:attrs];    }}

// 创造位置

率先把cell的莫斯中国科学技术大学学设置为self.edgeInsets.top不然这里会崩溃。然后抽取来item的个数,然后循环收取各样item的UICollectionViewLayoutAttributes,然后把它加入到attsArray,然后在- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect这些主意中央行政机关接再次来到attrsArray就能够。

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

-

// 获取indexPath地点cell对应的布局属性

(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath{UICollectionViewLayoutAttributes*attrs

[UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];CGFloatcollectionViewW =self.collectionView.frame.size.width;CGFloatw = (collectionViewW -self.edgeInsets.left -self.edgeInsets.right -(self.columnCount -1) *self.columnMargin) /self.columnCount;CGFloath = [self.delegate WaterFlowLayout:selfheightForRowAtIndexPath:indexPath.item itemWidth:w];NSIntegerdestColumn =0;CGFloatminColumnHeight = [self.columnHeights[0] doubleValue];for(NSIntegeri =0; i columnHeight) {            minColumnHeight = columnHeight;            destColumn = i;        }    }CGFloatx =self.edgeInsets.left destColumn * (w self.columnMargin);CGFloaty = minColumnHeight;if(y !=self.edgeInsets.top) {        y =self.rowMargin;    }    attrs.frame =CGRectMake(x, y, w, h);self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));CGFloatcolumnHeight = [self.columnHeights[destColumn] doubleValue];if(self.contentHeight < columnHeight) {self.contentHeight = columnHeight;    }returnattrs;}

上边这一个办法是一个钱打二17个结item的岗位的代码,首先抽取来indexPath的UICollectionViewLayoutAttributes对象,然后抽出来w,h,大旨代码如下:

NSIntegerdestColumn =0;CGFloatminColumnHeight = [self.columnHeights[0] doubleValue];for(NSIntegeri =0; i columnHeight) {            minColumnHeight = columnHeight;            destColumn = i;        }    }CGFloatx =self.edgeInsets.left destColumn * (w self.columnMargin);CGFloaty = minColumnHeight;if(y !=self.edgeInsets.top) {        y =self.rowMargin;    }

先是弄了二个标示destColumn来做记录是那一列的,然后定义三个minColumnHeight为最小的列的可观,抽取来self.columnHeights[0]的可观,这里默感到它就是小小的的,然后举办for循环遍历,抽取来i地方下边包车型客车万丈,借使这么些值小于从前的minColumnHeight,那么抽出来的那当中度正是纤维的莫斯中国科学技术大学学了,然后把i的值赋值给destColumn,然后x的值正是上面代码中的相加的结果,y的值正是承接增加间距

- (CGSize)collectionViewContentSize{//    CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];////    for (NSInteger i = 1; i < DefaultColumnCpunt; i ) {//        // 获得第i列的可观//        CGFloat columnHeight = [self.columnHeights[i] doubleValue];////        if (maxColumnHeight < columnHeight) {//            maxColumnHeight = columnHeight;//        }//    }returnCGSizeMake(0,self.contentHeight self.edgeInsets.bottom);}

代码在github上面

github

UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];

[self.attrsArray addObject:attrs];

}

}

/**

* 决定cell的排布

*/

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

{

return self.attrsArray;

}

/**

* 再次回到indexPath地点cell对应的布局属性

*/

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

{

// 创立布局属性

UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

// collectionView的宽度

CGFloat collectionViewW = self.collectionView.frame.size.width;

// 设置布局属性的frame

CGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;

CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:w];

// 找寻中度最短的那一列

NSInteger destColumn = 0;

CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];

for (NSInteger i = 1; i < self.columnCount; i ) {

// 猎取第i列的可观

CGFloat columnHeight = [self.columnHeights[i] doubleValue];

if (minColumnHeight > columnHeight) {

minColumnHeight = columnHeight;

destColumn = i;

}

}

CGFloat x = self.edgeInsets.left destColumn * (w self.columnMargin);

CGFloat y = minColumnHeight;

if (y != self.edgeInsets.top) {

y = self.rowMargin;

}

attrs.frame = CGRectMake(x, y, w, h);

// 更新最短那列的万丈

self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));

// 记录内容的莫大

CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];

if (self.contentHeight < columnHeight) {

self.contentHeight = columnHeight;

}

return attrs;

}

本文由星彩网app下载发布于计算机编程,转载请注明出处:承继UICollectionViewLayout自定义布局,瀑布流飞快完

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。