IOS简单实现瀑布流UICollectionView

UICollectionView 比tableView 灵活,功能也强大很多。系统实现了流式布局,但用处还有很多限制。

要想实现更灵活的布局,就咬重写UICollectionViewLayout。
先看下实现效果:

废话不多说,直接上代码:

先看WaterfallCollectionLayout.m

#import "WaterfallCollectionLayout.h"
#define colMargin 5
#define colCount 4
#define rolMargin 5
@interface WaterfallCollectionLayout ()
//数组存放每列的总高度
@property(nonatomic,strong)NSMutableArray* colsHeight;
//单元格宽度
@property(nonatomic,assign)CGFloat colWidth;
@end

该类要重写以下方法:

//完成布局前的初始工作
-(void)prepareLayout;

//collectionView的内容尺寸
-(CGSize)collectionViewContentSize;

//为每个item设置属性
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;

//获取制定范围的所有item的属性
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

每次调用会清空colsHeight数组里的信息:

//完成布局前的初始工作
-(void)prepareLayout{
  [super prepareLayout];
  self.colWidth =( self.collectionView.frame.size.width - (colCount+1)*colMargin )/colCount;
  //让它重新加载
  self.colsHeight = nil;
}
通过遍历colHeight数组里的所有列来获得最长的那一列,返回contentsize
//collectionView的内容尺寸
-(CGSize)collectionViewContentSize{
  NSNumber * longest = self.colsHeight[0];
  for (NSInteger i =0;i<self.colsHeight.count;i++) {
    NSNumber* rolHeight = self.colsHeight[i];
    if(longest.floatValue<rolHeight.floatValue){
      longest = rolHeight;
    }
  }
  return CGSizeMake(self.collectionView.frame.size.width, longest.floatValue);
}

每个cell要出来时这个方法会被调用,在此方法中设置该cell的frame。

注意heightBlock是外部控制器传进来的block用以计算每个cell的高度,现在我只是设置了随机数。如果没有传block进来我这里直接让他崩溃了。

//为每个item设置属性
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
  UICollectionViewLayoutAttributes* attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
  NSNumber * shortest = self.colsHeight[0];
  NSInteger shortCol = 0;
  for (NSInteger i =0;i<self.colsHeight.count;i++) {
    NSNumber* rolHeight = self.colsHeight[i];
    if(shortest.floatValue>rolHeight.floatValue){
      shortest = rolHeight;
      shortCol=i;
    }
  }
  CGFloat x = (shortCol+1)*colMargin+ shortCol * self.colWidth;
  CGFloat y = shortest.floatValue+colMargin;

  //获取cell高度
  CGFloat height=0;
  NSAssert(self.heightBlock!=nil, @"未实现计算高度的block ");
  if(self.heightBlock){
    height = self.heightBlock(indexPath);
  }
  attr.frame= CGRectMake(x, y, self.colWidth, height);
  self.colsHeight[shortCol]=@(shortest.floatValue+colMargin+height);

  return attr;
}
//获取所有item的属性
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
  NSMutableArray* array = [NSMutableArray array];
  NSInteger items = [self.collectionView numberOfItemsInSection:0];
  for (int i = 0; i<items;i++) {
    UICollectionViewLayoutAttributes* attr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
    [array addObject:attr];
  }
  return array;
}

实现下列方法会在出现新的cell时重新布局并调用preparelayout方法

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
  return YES;
}

每列高度的存放,初始高度可以改,我这里是0

-(NSMutableArray *)colsHeight{
  if(!_colsHeight){
    NSMutableArray * array = [NSMutableArray array];
    for(int i =0;i<colCount;i++){
      //这里可以设置初始高度
      [array addObject:@(0)];
    }
    _colsHeight = [array mutableCopy];
  }
  return _colsHeight;
}

再来看看控制器里就是这么简单

#pragma mark getter-setter
-(UICollectionView *)collectionView{
  if(!_collectionView){
    _collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:self.layout];
    _collectionView.backgroundColor = [UIColor whiteColor];
    _collectionView.delegate=self;
    _collectionView.dataSource=self;
    [_collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:identifer];
  }
  return _collectionView;
}
-(UICollectionViewLayout *)layout{
  if(!_layout){
    _layout = [[WaterfallCollectionLayout alloc]initWithItemsHeightBlock:^CGFloat(NSIndexPath *index) {
      return [self.heightArr[index.item] floatValue];
    }];

  }
  return _layout;
}
-(NSArray *)heightArr{
  if(!_heightArr){
    //随机生成高度
    NSMutableArray *arr = [NSMutableArray array];
    for (int i = 0; i<100; i++) {
      [arr addObject:@(arc4random()%50+80)];
    }
    _heightArr = [arr copy];
  }
  return _heightArr;
}

关于瀑布流的文章特别多,本文就是为大家分享了IOS简单实现瀑布流的方法,希望对大家的学习有所帮助。

(0)

相关推荐

  • iOS应用中UICollectionViewCell定制Button

    UICollectionViewCell定制Button 效果 特点 1.能够动态设置每行显示的按钮的个数,以及控件的摆放格式 2.实现单选或者多选的功能,实现点击事件 3.自定制按钮的显示样式 用法 1.下载源码后,将文件中的GridCollectionView.h/.m文件, CustomCollectionViewCell.h/.m文件, TypeCellClass.h/.m文件导入工程中. 2.注意:你所创建的cell要继承CustomCollectionViewCell.然后你的cel

  • iOS自定义UICollectionViewFlowLayout实现图片浏览效果

    以前瀑布流的时候使用过UICollectionView,但是那时使用的是系统自带的UICollectionViewFlowLayout布局,今天看文章,看到UICollectionViewFlowLayout自定义相关的东西,于是动手写了一个简单图片浏览的demo,熟练一些UICollectionViewFlowLayout自定义布局. #import <UIKit/UIKit.h> @interface JWCollectionViewFlowLayout : UICollectionVie

  • Swift下使用UICollectionView 实现长按拖拽功能

    导读 简单用Swift写了一个collectionview的拖拽点击排序效果; 拖拽排序是新闻类的App可以说是必有的交互设计,如今日头条,网易新闻等. GitHub地址:https://github.com/wangliujiayou/Swift-dragLabel 欢迎Star. 效果 主要代码 手势长按移动 1.给CollectionViewCell添加一个长按手势. private lazy var collectionView: UICollectionView = { let clv

  • IOS使用UICollectionView实现无限轮播效果

    一.案例演示 本案例Demo演示的是一个首页轮播的案例,支持手动轮播和自动轮播.知识点主要集中在UICollectionView和NSTimer的使用. 二.知识储备 2.1.UICollectionView横向布局 只需要设置UICollectionViewFlowLayout的scrollDirection为UICollectionViewScrollDirectionHorizontal即可. 2.2.NSTimer的基本使用 NSTimer的初始化: 复制代码 代码如下: + (NSTi

  • iOS中关于Swift UICollectionView横向分页的问题

    下面通过图文并茂的形式给大家介绍UICollectionView横向分页的问题,具体内容详情如下所示: 情况 直接看图 滚前 滚后 已经设置collectionView的isPagingEnabled为true了,可是出现了这种情况,原因就是collectionView的contentSize不够. <UICollectionView: 0x7fc565076000; frame = (0 0; 375 197); clipsToBounds = YES; gestureRecognizers

  • iOS 解决UICollectionView 计算 Cell 大小的问题

    前言 API 不熟悉导致的问题,想当然的去理解果然会出问题,这里记录一下 UICollectionView 使用问题. 正文 陷阱一:minimumLineSpacing.minimumInteritemSpacing 很容易就把这两个属性设置为 0 ,这两个属性是最小行间距和最小列间距,注意是最小!!也就是说实际上可以 > 0 ,并不是间距就是 0 陷阱二:sectionInset 设置 cell 的边距.一开始我以为是每一个 cell 的边距,相邻之间会叠加效果,实际上并不是这样的,这个属性

  • IOS简单实现瀑布流UICollectionView

    UICollectionView 比tableView 灵活,功能也强大很多.系统实现了流式布局,但用处还有很多限制. 要想实现更灵活的布局,就咬重写UICollectionViewLayout. 先看下实现效果: 废话不多说,直接上代码: 先看WaterfallCollectionLayout.m #import "WaterfallCollectionLayout.h" #define colMargin 5 #define colCount 4 #define rolMargin

  • 利用JS实现简单的瀑布流加载图片效果

    今天学习了一个瀑布流加载效果,很多网站都有瀑布流效果,瀑布流就是很多产品显示在网页上,宽相同,高度不同,表现为多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部. 原理是: 1.设定一行中的列数: 2.取第一行中每一个div的高度并把每一个高度放进一个数组中: 3.算出数组中最小高度的index值: 4.把第二行的第一个div放到最小高度的div的下方并把重新算出的高度值放进数组中,重新计算最小高度的index值: 5.以此类推实现多栏布局的瀑布流效果: 6.如果最后一

  • 一个简单的瀑布流效果(主体形式自写)

    闲着没事,自己写了个瀑布流,我个人写脚本或者是网页的习惯是:只参考别人的效果,很少参考别人的代码,有时侯我宁愿用审查元素来推断代码,也不愿去看源代码.我不知道这个习惯好不好.虽然中间过程是花了我不少时间,但是我做的东西的每一个细节我都还能记清楚(当然肯定后来会忘),因为是我实现的.下面说正题: 瀑布流的主体即为几个ul标签,新增加的元素以 li的形式按照当前 ul的高度有选择性的插入到某个ul下. 主体形式如下: 复制代码 代码如下: <div id="main"> <

  • Flutter瀑布流仿写原生的复用机制详解

    目录 废话开篇: 先看复用效果 复用状态打印 问题一.实现思路是什么? 问题二.UI布局代码分析. 总结 废话开篇: iOS与android在实现列表界面的时候是有重用机制的,目的就是减少内存开销,用时间换空间.个人感觉flutter并没有特别强调复用,关于listView.builder 的"复用"个人感觉应该是销毁跟重建的过程,所以这里用flutter实现了简单的复用机制.代码拙劣,大神勿喷,共同进步 先看复用效果 复用状态打印 右侧是简单实现瀑布流界面,里面显示的是一共有39个W

  • iOS瀑布流的简单实现(Swift)

    这段时间突然想到一个很久之前用到的知识-瀑布流,本来想用一个简单的方法,发现自己走入了歧途,最终只能狠下心来重写UICollectionViewFlowLayout.下面我将用两种方法实现瀑布流,以及会介绍第一种实现的bug. <1>第一种 效果图如下所示: 这种实现方法的思路: 1)首先调用随机函数,产生随机高度,并把它保存到数组中 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollection

  • ios基于UICollectionView实现横向瀑布流

    在网上找了许久,一直没有发现有提供横向瀑布流效果的.在项目中用到了我就在垂直瀑布流的基础上,进行了修改,做出了横向瀑布流的效果.同时也对一些UICollectionView的属性进行简单的注释,方便以后查阅. 1.首先要写一个继承与NSObject的布局类,记录每一行(列)目前的宽度(高度).再添加一个新的cell的时候进行判断比较,添加到最短的那一行或一列上. 2.横向的布局类入下,垂直的话就是讲对应的X Y轴数据进行调整即可. WaterfallFlowLayout为布局类,继承与NSObj

  • 详解IOS中如何实现瀑布流效果

    首先是效果演示 特点:可以自由设置瀑布流的总列数(效果演示为2列) 虽然iphone手机的系统相册没有使用这种布局效果,瀑布流依然是一种很常见的布局方式!!!下面来详细介绍如何实现这种布局. 首先使用的类是UICollectionView 我们要做的是自定义UICollectionViewCell和UICollectionViewLayout 1.自定义UICollectionViewCell类,只需要一个UIImageView即可,frame占满整个cell. 2.重点是自定义UICollec

  • 使用JS实现图片展示瀑布流效果(简单实例)

    不知大家有没有发现,一般的图片展示网站都会使用瀑布流效果,所谓的瀑布流 就是网站内的图片不会一下子全缓存出来,而是等你滚动到一定的距离的时候, 下面的图片才会继续缓存,并且图片也是随机出现的,只是宽度一样,高度并不 一样,高高低低就像瀑布一样,所以叫做瀑布流效果.下面我把代码给大家,大家 随便下几张图片试试. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&qu

  • jQuery图片瀑布流的简单实现代码

    简单版的Jquery实现图片瀑布流思路,供大家参考,具体内容如下 注意:本篇文章基于知道每张图片的实际尺寸的情况下 特点:列数自适应,图片宽度固定 已知BUG: 像本案例中的刚好5张图片循环显示且只有5列的情况下会有问题,解决办法就是给予样式的时候不按顺序,而是先将图片放在top值最低的列 1.预备 1.基础html <div id="main"> <div class="img-item"><img src="images/

  • 用瀑布流的方式在网页上插入图片的简单实现方法

    当我们的网页需要插入很多图片的时候,为了美观,我们可以选择用瀑布流的方法插入图片 首先我们在body里面放入我们需要展示的图片 <div id="box"> <div class="dinwei"> <div class="pic"> <img src="image/1.jpg"> </div> </div> <div class="din

随机推荐