IOS 瀑布流UICollectionView实现


在实现瀑布流之前先来看看瀑布流的雏形(此方法的雏形 UICollectionView)

对于UICollectionView我们有几点注意事项

  • 它和tableView不一样,ContentView的内容完全需要我们自己去添加。
  • 它与tableview相比,他的初始化需要FlowLayout并且大部分操作在其上。
  • UIcollectionView的实用性极强,虽然有时他并不是最好的解决方案,但是它可以很灵活的实现各种效果。

图(一)

如图,模拟器上展示的是很多方格,但是值得注意的是他们是有规则的。

虽然看上去很整洁但是并不美观。

我们所说的要实现瀑布流就是要实现它的不整洁,但是规律(这里我说的是规律)

正题

前面说了UIcollectionView的大部分操作在FlowLayout上,当然也包括格局部署。

为了实现瀑布流我们所要实现的便是改变他的格局部署。

在写代码前先确定一下实现思想。

  • 需要什么???

    • 首先我们需要确定瀑布流的显示风格
    • 然后根据确定好的风格进行整体设计
    • 最后通过细节的处理完善代码
      • 我们需要什么样的风格???

        • 我们需要的是实现将上面图片中的布局改变为不等高的效果
        • 说的俗一点就是像名字一样,像瀑布流水一样
      • 整体该如何设计???
        • 整体采用与上面图片一样的设计方法,每个模块都是一个cell
        • 确保最上面一行的cell的y值相同(美观)
        • 确保不不会出现一列特别长,一列特别短的效果
      • 初步细节有哪些???
        • 因为每个cell的height不同,所以我们要考虑放置的顺序应该是什么
        • 精简代码(这是每个项目必须注意的)

实现效果

代码

下面是实现的代码部分(不提供demo了 很简单)

我在注释中简单介绍。

---

//
// ViewController.m
// CX-瀑布流UIcollectionView实现
//
// Created by ma c on 16/4/8.
// Copyright © 2016年 bjsxt. All rights reserved.
// #import "ViewController.h"
#import "CXCollectionViewCell.h"
#import "CXCollectionViewLayout.h" static NSString * identifier = @"cellID"; @interface ViewController ()<UICollectionViewDataSource>
//所要展示的UICollectionView
@property (nonatomic, strong) UICollectionView * collectionView; @end @implementation ViewController #pragma mark - <懒加载>
- (UICollectionView *)collectionView {
if (!_collectionView) {
//初始化我们自定义的flowLayout
CXCollectionViewLayout * flowLayout = [[CXCollectionViewLayout alloc]init];
//初始化collectionView
_collectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
//设置数据源(collectionView的命根子)
_collectionView.dataSource = self;
//注册我们自定义的cell
[_collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CXCollectionViewCell class]) bundle:nil] forCellWithReuseIdentifier:identifier];
}
return _collectionView;
} #pragma mark - <life> - (void)viewDidLoad {
[super viewDidLoad];
//在self.view上添加---
[self.view addSubview:self.collectionView];
}
#pragma mark - <UICollectionViewDataSource>
//这里返回的是item的个数 返回100
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return ;
}
//这里返回的是cell 我们可以在这里进行一些简单的操作
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ CXCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
//为了瀑布流的实现细节我们添加的Label cell.label.text = [NSString stringWithFormat:@"%zd",indexPath.item];
//cell的背景色
cell.backgroundColor = [UIColor orangeColor]; return cell;
} @end

---

//
// CXCollectionViewLayout.m
// CX-瀑布流UIcollectionView实现
//
// Created by ma c on 16/4/8.
// Copyright © 2016年 bjsxt. All rights reserved.
// #import "CXCollectionViewLayout.h" //瀑布流的列数
static NSInteger CXcolumnCount = ;
//瀑布流的内边距
static UIEdgeInsets CXdefaultEdgeInsets = {,,,};
//cell的列间距
static NSInteger CXcolumnMagin = ;
//cell的行间距
static NSInteger CXrowMagin = ; @interface CXCollectionViewLayout () //存放所有cell 的布局属性
@property (nonatomic, strong) NSMutableArray * CXattrsArray;
//缩放所有列的高度
@property (nonatomic, strong) NSMutableArray * CXcolumnHeights; @end @implementation CXCollectionViewLayout #pragma mark - <懒加载>
- (NSMutableArray *)CXattrsArray{
if (!_CXattrsArray) {
_CXattrsArray = [NSMutableArray array];
}
return _CXattrsArray;
} - (NSMutableArray *)CXcolumnHeights{
if (!_CXcolumnHeights) {
_CXcolumnHeights = [NSMutableArray array];
}
return _CXcolumnHeights;
}
#pragma mark - <准备布局>
//准备布局(布局前自动执行)
- (void) prepareLayout{
//重写此方法一定要记得super
[super prepareLayout]; //在实际操作中我们的数据并不会固定不变的,因此我们每次布局前最好要清空之前存储的属性
//清空存放所有列的高度
//清空存放所有cell的不去属性
[self.CXcolumnHeights removeAllObjects];
[self.CXattrsArray removeAllObjects];
//首先为第一行的cell附高度
for (NSInteger i = ; i < CXcolumnCount; i ++) {
//数组里只能存放对象
[self.CXcolumnHeights addObject:@(CXdefaultEdgeInsets.top)];
}
//下面开始创建每一个cell的布局属性 并且添加到存储cell布局属性的数组中
//cell总个数 因为这里只要一个section
NSInteger count = [self.collectionView numberOfItemsInSection:];
for (NSInteger i = ; i < count; i ++) {
// 创建位置 即indexPath
NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:];
//获取indexPath对应的cell布局属性
UICollectionViewLayoutAttributes * attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
//把获取到的布局属性添加到数组中
[self.CXattrsArray addObject:attributes];
}
//准备布局的工作到这里就结束了
}
//返回所有cell布局属性 及整体cell 的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
return self.CXattrsArray;
}
//返回cell 的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
//创建布局属性
UICollectionViewLayoutAttributes * CXattributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //获取collectionView 的宽
CGFloat collectionViewWidth = self.collectionView.frame.size.width;
//下面的一部分是获取cell的frame(布局属性)
CGFloat width;
CGFloat height;
CGFloat X;
CGFloat Y;
//获取width
width = (collectionViewWidth - CXdefaultEdgeInsets.left - CXdefaultEdgeInsets.right - (CXcolumnCount - ) * CXcolumnMagin) / CXcolumnCount;
//获取height
//在实际开发中heigh并不是真正的随机 而是根据数据来决定height 在这里展示初步的介绍其原理 因此采用大于100小于150的随机数
height = + arc4random_uniform();
//获取X (瀑布流的实现重点就在cell的X,Y值获取)
//设置一个列数的中间变量
NSInteger tempColumn = ;
//设置高度小的中间变量 在这里我们把第0列的高度给他,这样可以减少循环次数,提高效率
CGFloat minColumnHeight = [self.CXcolumnHeights[] doubleValue];
for (NSInteger i = ; i < CXcolumnCount; i ++) {
if (minColumnHeight > [self.CXcolumnHeights[i] doubleValue]) {
minColumnHeight = [self.CXcolumnHeights[i] doubleValue];
tempColumn = i;
}
}
X = CXdefaultEdgeInsets.left + (width + CXcolumnMagin) * tempColumn;
//获取Y
Y = minColumnHeight;
if (Y != CXdefaultEdgeInsets.top) {
Y += CXrowMagin;
}
//设置cell的frame
CXattributes.frame = CGRectMake(X, Y, width, height);
//更新高度最矮的那列的高度
self.CXcolumnHeights[tempColumn] = @(CGRectGetMaxY(CXattributes.frame)); return CXattributes;
}
//返回collegeView的Content的大小
- (CGSize)collectionViewContentSize{
//虽说返回的是大小,但是我们这里主要的是height
CGFloat maxColumnHeight = [self.CXcolumnHeights[] doubleValue];
for (NSInteger i = ; i < CXcolumnCount; i++) { CGFloat columnHeight = [self.CXcolumnHeights[i] doubleValue]; if (maxColumnHeight < columnHeight) {
maxColumnHeight = columnHeight;
}
}
return CGSizeMake(, maxColumnHeight + CXdefaultEdgeInsets.bottom); } @end

到此为止瀑布流的实现也就结束了。

在这里说明几点值得注意的地方。

  • 瀑布流中的cell排布顺势是根据当前列的高度有关的(例如:如果当前第三列是最短的,但是按正常情况下cell应该排在第一列,那么这个时候,新的cell会排在第三列,这是为了避免某一列高度特别长或某一列的高度特别短)
  • 在实际应用中通常cell的大小是根据数据的来处理的
  • UIcollectionView的content的高度是不确定的,因此我们要根据内容设定高度。
  • 当涉及到刷新的时候我们要注意cell的布局属性是否在新数据到来前清空了。

IOS 瀑布流UICollectionView实现的更多相关文章

  1. iOS 瀑布流之栅格布局

    代码地址如下:http://www.demodashi.com/demo/14760.html 一 .效果预览 二.确定需求 由下面的需求示意图可知模块的最小单位是正方形,边长是屏幕宽除去边距间隔后的 ...

  2. iOS 瀑布流封装

    代码地址如下:http://www.demodashi.com/demo/12284.html 一.效果预览 功能描述:WSLWaterFlowLayout 是在继承于UICollectionView ...

  3. IOS 瀑布流

    本篇博客应该算的上CollectionView的高级应用了,从iOS开发之窥探UICollectionViewController(一)到今天的(五),可谓是由浅入深的窥探了一下UICollectio ...

  4. iOS瀑布流实现(Swift)

    这段时间突然想到一个很久之前用到的知识-瀑布流,本来想用一个简单的方法,发现自己走入了歧途,最终只能狠下心来重写UICollectionViewFlowLayout.下面我将用两种方法实现瀑布流,以及 ...

  5. iOS 瀑布流的Demo

    /** * 瀑布流Demo的主要代码,若想看完整的代码请到下面链接去下载 * * 链接: https://pan.baidu.com/s/1slByAHB 密码: r3q6 */ #import &l ...

  6. iOS 瀑布流的基本原理

    /** * 源代码链接 * 链接: https://pan.baidu.com/s/1nvLamEX 密码: kya5 */ #import <UIKit/UIKit.h> @interf ...

  7. ios 瀑布流的那些事情

    转载: 屎壳郎情调-成长日记 首先要知道:瀑布流的核心就是要获取到图片的长宽 网上的很多例子都是加载本地图片的 对于新手而言 改成加载网络图片的确是有点压力的  因为本地的图片 我们是很容易就能获取到 ...

  8. ios瀑布流

    http://blog.csdn.net/shenjx1225/article/details/9037631

  9. iOS开发笔记15:地图坐标转换那些事、block引用循环/weak–strong dance、UICollectionviewLayout及瀑布流、图层混合

    1.地图坐标转换那些事 (1)投影坐标系与地理坐标系 地理坐标系使用三维球面来定义地球上的位置,单位即经纬度.但经纬度无法精确测量距离戒面积,也难以在平面地图戒计算机屏幕上显示数据.通过投影的方式可以 ...

随机推荐

  1. Linux 时钟与计时器

    对 Linux 系统来说,时钟和计时器是两个十分重要的概念.时钟反应的是绝对时间,也可认为是实时时间.计时器反应的则是相对时间,即相对于系统启动后的计时.操作系统内核需要管理运行时间(uptime)和 ...

  2. 一个简单的 ASP.NET MVC 例子演示如何在 Knockout JS 的配合下,使用 TypeScript 。

    前言 TypeScript 是一种由微软开发的自由和开源的编程语言.它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程.安德斯·海尔斯伯格,C#的首席架 ...

  3. Uvaoj 11248 Frequency Hopping(Dinic求最小割)

    题意:1到n节点(节点之间有一定的容量),需要流过C的流量,问是否可以?如果可以输出possible, 否则如果可以扩大任意一条边的容量 可以达到目的,那么输出possible option:接着输出 ...

  4. Android manifest之系统自带的permission

    Android manifest之系统自带的permission 本文描述Android系统自带的permission.点击查看:“关于permission的原始定义和说明”.点击查看:“Androi ...

  5. 在做Android开发的,如何去掉滚动view在尽头时的阴影效果

    不经意的在开发中,发现qq的侧滑几乎没有阴影效果,就是拉到边界没有时出现的效果:于是在网上找了下,发现很简单的设置 只要在xml布局文件的滚动或者侧滑控件中加入如下样式: android:overSc ...

  6. 浅析LRU(K-V)缓存

    LRU(Least Recently Used)算法是缓存技术中的一种常见思想,顾名思义,最近最少使用,也就是说有两个维度来衡量,一个是时间(最近),一个频率(最少).如果需要按优先级来对缓存中的K- ...

  7. Mysql学习笔记(十)存储过程与函数 + 知识点补充(having与where的区别)

    学习内容:存储程序与函数...这一章学的我是云里雾里的... 1.存储过程...   Mysql存储过程是从mysql 5.0开始增加的一个新功能.存储过程的优点其实有很多,不过我觉得存储过程最重要的 ...

  8. 数论 - 算数基本定理的运用 --- nefu 118 : n!后面有多少个0

     题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemshow.php Mean: 略. analyse: 刚开始想了半天都没想出来,数据这么大,难道是有什么 ...

  9. JAVA - 大数类详解

    写在前面 对于ACMer来说,java语言最大的优势就是BigInteger,Bigdecimal,String三个类. 这三个类分别是高精度整数,高精度浮点数和字符串,之所以说这个是它的优势是因为j ...

  10. 新增的querySelector、querySelectorAll测试

    从IE9开始DOM开始支持支持CSS的选择器了,DOM提供了两个接口 querySelector 得到一个DOM querySelectorAll 得到一组DOM 一个个的解释这些选择器也没有必要,我 ...