ios基于UICollectionView实现横向瀑布流
程序员文章站
2022-05-26 16:22:03
在网上找了许久,一直没有发现有提供横向瀑布流效果的。在项目中用到了我就在垂直瀑布流的基础上,进行了修改,做出了横向瀑布流的效果。同时也对一些uicollectionview...
在网上找了许久,一直没有发现有提供横向瀑布流效果的。在项目中用到了我就在垂直瀑布流的基础上,进行了修改,做出了横向瀑布流的效果。同时也对一些uicollectionview的属性进行简单的注释,方便以后查阅。
1、首先要写一个继承与nsobject的布局类,记录每一行(列)目前的宽度(高度)。再添加一个新的cell的时候进行判断比较,添加到最短的那一行或一列上。
2、横向的布局类入下,垂直的话就是讲对应的x y轴数据进行调整即可。
waterfallflowlayout为布局类,继承与nsobject。.h文件入下
#import <uikit/uikit.h> // 类的前置声明 @class waterfallflowlayout; @protocol waterfallflowlayoutdelegate <nsobject> // 动态获取 item 宽度 - (cgfloat) waterfallflowlayout:(waterfallflowlayout *) layout widthforitematindexpath:(nsindexpath *) indexpath; @end @interface waterfallflowlayout : uicollectionviewlayout @property (nonatomic,assign) id <waterfallflowlayoutdelegate> delegate; @property (nonatomic) nsinteger numberofcolumns; @property (nonatomic) cgfloat minimumlinespacing; @property (nonatomic) cgfloat minimuminteritemspacing; @property (nonatomic) uiedgeinsets sectioninset; @end
waterfallflowlayout为布局类,继承与nsobject。.m文件入下
#import "waterfallflowlayout.h" @interface waterfallflowlayout () { // 用于记录每一列布局到的宽度 nsmutablearray * _widthofcolumns; // 用于保存所有item的属性 (frame) nsmutablearray * _itemsattributes; } @end @implementation waterfallflowlayout - (void) setnumberofcolumns:(nsinteger)numberofcolumns { if (_numberofcolumns != numberofcolumns) { _numberofcolumns = numberofcolumns; // 让原有布局失效,需要重新布局 [self invalidatelayout]; } } - (void)setminimumlinespacing:(cgfloat)minimumlinespacing { if (_minimumlinespacing != minimumlinespacing) { _minimumlinespacing = minimumlinespacing; [self invalidatelayout]; } } - (void)setminimuminteritemspacing:(cgfloat)minimuminteritemspacing { if (_minimuminteritemspacing != minimuminteritemspacing) { _minimuminteritemspacing = minimuminteritemspacing; [self invalidatelayout]; } } - (void)setsectioninset:(uiedgeinsets)sectioninset { if (!uiedgeinsetsequaltoedgeinsets(_sectioninset, sectioninset)) { _sectioninset = sectioninset; [self invalidatelayout]; } } //重写方法 1: 准备布局 -(void)preparelayout { [super preparelayout]; // 真正的布局在这里完成 if (_itemsattributes) { [_itemsattributes removeallobjects]; }else { _itemsattributes = [[nsmutablearray alloc] init]; } if (_widthofcolumns) { [_widthofcolumns removeallobjects]; }else { _widthofcolumns = [[nsmutablearray alloc] init]; } for (nsinteger i = 0; i < self.numberofcolumns; i++) { // 初始化每一列的宽度(默认为上边距) // _heightofcolumns[i] = @(self.sectioninset.top); [_widthofcolumns addobject:@(self.sectioninset.left)]; } // item的总数 nsinteger count = [self.collectionview numberofitemsinsection:0]; // cgfloat itemwidth = (self.collectionview.frame.size.width - self.sectioninset.left - self.sectioninset.right - (_numberofcolumns-1) * _minimuminteritemspacing )/_numberofcolumns; // 总的高度 (集合视图的宽度) cgfloat totalheight = self.collectionview.frame.size.height; // 有效的高度 (出去间隔及边界) cgfloat validheight = totalheight - self.sectioninset.top - self.self.sectioninset.bottom - (self.numberofcolumns-1) * self.minimuminteritemspacing; // 每一个item的高度 cgfloat itemheight = validheight/self.numberofcolumns; // 设置item的默认宽度 cgfloat itemwidth = itemheight; for (nsinteger i = 0; i<count; i++) { // 最短列的下标 nsinteger index = [self indexofshortestcolumn]; cgfloat originy = self.sectioninset.top + index * (itemheight +self.minimuminteritemspacing); cgfloat originx = [_widthofcolumns[index] floatvalue]; // 构造 indexpath nsindexpath * indexpath = [nsindexpath indexpathforitem:i insection:0]; // 动态的获取宽度 if ([self.delegate respondstoselector:@selector(waterfallflowlayout:widthforitematindexpath:)]) { itemwidth = [self.delegate waterfallflowlayout:self widthforitematindexpath:indexpath]; } uicollectionviewlayoutattributes * attr = [uicollectionviewlayoutattributes layoutattributesforcellwithindexpath:indexpath]; attr.frame = cgrectmake(originx, originy, itemwidth, itemheight); // 保存 item 的属性 到数组中 [_itemsattributes addobject:attr]; // 更新布局到的一列(最短列) 的高度 _widthofcolumns[index] = @(originx + itemwidth + self.minimumlinespacing); } // 刷新显示 [self.collectionview reloaddata]; } //重写方法 2: 返回指定区域的item的属性(frame) - (nsarray<uicollectionviewlayoutattributes *> *)layoutattributesforelementsinrect:(cgrect)rect { nsmutablearray * array = [nsmutablearray array]; for (uicollectionviewlayoutattributes * attr in _itemsattributes) { // 判断两个矩形是否有交集 if (cgrectintersectsrect(attr.frame, rect)) { [array addobject:attr]; } } return array; } //重写方法 3: 返回内容的尺寸 -(cgsize)collectionviewcontentsize { cgfloat height = self.collectionview.frame.size.height; nsinteger index = [self indexoflongestcolumn]; cgfloat width = [_widthofcolumns[index] floatvalue] + self.sectioninset.right - self.minimumlinespacing; return cgsizemake(width, height); } - (nsinteger) indexoflongestcolumn { nsinteger index = 0; for (nsinteger i = 0; i<_numberofcolumns; i++) { if ([_widthofcolumns[i] floatvalue] > [_widthofcolumns[index] floatvalue]) { index = i; } } return index; } - (nsinteger) indexofshortestcolumn { nsinteger index = 0; for (nsinteger i = 0; i<_numberofcolumns; i++) { if ([_widthofcolumns[i] floatvalue] < [_widthofcolumns[index] floatvalue]) { index = i; } } return index; } @end
3、上边的这个布局类可以直接复制粘贴下来。然后就是创建你的uicollectionview
在collectionview的cell中可以直接创建imageview或者是label添加到cell上,用来显示数据。
collectionview默认section缩进左右是0
调节横向cell间距
layout.minimumlinespacing = 10;
调节纵向cell间距
layout.minimuminteritemspacing = 20;
调节瀑布流显示的行数,当然了你的collectionview的高(宽)足够显示几行(列)就会自动显示多上行(列);
layout.numberofcolumns = 3;
#import "rootviewcontroller.h" #import "waterfallflowlayout.h" @interface rootviewcontroller () <uicollectionviewdatasource,uicollectionviewdelegateflowlayout,waterfallflowlayoutdelegate> { uicollectionview * _collectionview; } @end @implementation rootviewcontroller - (void)dealloc { [_collectionview release]; [super dealloc]; } - (void)viewdidload { [super viewdidload]; // 创建集合视图 [self createcollectionview]; } - (uicollectionviewlayout *)createlayout { #if 1 waterfallflowlayout * layout = [[waterfallflowlayout alloc] init]; layout.sectioninset = uiedgeinsetsmake(20, 20, 20, 20); layout.minimumlinespacing = 10; layout.minimuminteritemspacing = 20; layout.numberofcolumns = 3; layout.delegate = self; [self performselector:@selector(changelayout:) withobject:layout afterdelay:3]; #else uicollectionviewflowlayout * layout = [[uicollectionviewflowlayout alloc] init]; layout.minimumlinespacing = 10; layout.itemsize = cgsizemake(150, 100); layout.sectioninset = uiedgeinsetsmake(10, 10, 10, 10); #endif return [layout autorelease]; } - (void)changelayout:(waterfallflowlayout *)layout { layout.numberofcolumns = 3; } - (void)createcollectionview { cgrect frame = cgrectmake(0, 20, view_width, view_height-20); _collectionview = [[uicollectionview alloc] initwithframe:frame collectionviewlayout:[self createlayout]]; _collectionview.backgroundcolor = [uicolor cyancolor]; // 设置代理 _collectionview.delegate = self; _collectionview.datasource = self; // 注册cell 类型 及 复用标识 [_collectionview registerclass:[uicollectionviewcell class] forcellwithreuseidentifier:@"cellid"]; [self.view addsubview:_collectionview]; } #pragma mark - uicollectionviewdatasource - (nsinteger)collectionview:(uicollectionview *)collectionview numberofitemsinsection:(nsinteger)section { return 102; } - (uicollectionviewcell *)collectionview:(uicollectionview *)collectionview cellforitematindexpath:(nsindexpath *)indexpath { uicollectionviewcell * cell = [collectionview dequeuereusablecellwithreuseidentifier:@"cellid" forindexpath:indexpath]; uilabel * label = nil; nsarray * array = cell.contentview.subviews; if (array.count) { label = array[0]; }else { label = [[uilabel alloc] init]; // label.frame = cell.bounds; label.textalignment = nstextalignmentcenter; label.font = [uifont systemfontofsize:50]; [cell.contentview addsubview:label]; [label release]; } label.frame = cell.bounds; label.text = [nsstring stringwithformat:@"%ld",indexpath.item]; label.textcolor = [uicolor whitecolor]; cell.backgroundcolor = randomcolor; return cell; } - (cgsize) collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout *)collectionviewlayout sizeforitematindexpath:(nsindexpath *)indexpath { return cgsizemake( arc4random()%100+200, 110); } -(cgfloat) waterfallflowlayout:(waterfallflowlayout *)layout widthforitematindexpath:(nsindexpath *)indexpath{ return arc4random()%150+50; } -(void)collectionview:(uicollectionview *)collectionview didselectitematindexpath:(nsindexpath *)indexpath{ nslog(@"点击了第 %ld 组,第 %ld 行",indexpath.section,indexpath.row); } - (void)didreceivememorywarning { [super didreceivememorywarning]; } @end
实现的效果如下
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。