当前位置: 移动技术网 > IT编程>移动开发>IOS > ios基于UICollectionView实现横向瀑布流

ios基于UICollectionView实现横向瀑布流

2019年07月23日  | 移动技术网IT编程  | 我要评论

穿越时空之血缘羁绊,susu,美德威钢琴

在网上找了许久,一直没有发现有提供横向瀑布流效果的。在项目中用到了我就在垂直瀑布流的基础上,进行了修改,做出了横向瀑布流的效果。同时也对一些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

实现的效果如下

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网