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. codeforces Fedor and New Game

    #include<iostream> #include<stack> #include<cstring> #include<cstdio> #inclu ...

  2. 编写高质量JS代码的68个有效方法(十三)

    No.61.不要阻塞I/O事件队列 Tips: 异步API使用回调函数来延缓处理代价高昂的操作以避免阻塞主应用程序 JavaScript并发的接收事件,但会使用一个事件队列按序地处理事件处理程序 在应 ...

  3. BABOK2主要概要输入输出图

  4. 禁用mac Command w

    事情是这样的:历经各种调查,终于定位到了一个bug,正在我准确Command + 数字 切换下iterm2的窗口时,让我懵逼的事情发生了,我们终端不见了,对不见了.心里万马奔腾啊.什么鬼?原来自己误按 ...

  5. Sapi 添加语法的文章(转载)

    最近在做SAPI方面的工作,比较详细的中文资料不多,遇到各种问题,本来想着做完了项目总结一下,今天看到这篇文章,对于SAPI加载识别语法方面的描述十分详细,先转过来做个备份,谢谢原文博主:djyang ...

  6. 分享一下我封装iOS自定义控件的体会,附上三个好用的控件Demo <时间选择器&多行输入框&日期选择器>

    前段时间有小伙伴问到我:"这样的控件该怎么做呢?",我感觉是个比较简单的控件,可能对于入行不久的同志思路没有很清晰吧.趁着最近工作不忙,就来这里分享一下我封装自定义控件的几点体会吧 ...

  7. 一些有用的UtilityExtend小方法

    public static bool StartBy(this string thisValue, params string[] startBy) { foreach (string item in ...

  8. C#关键字

    关键字 abstract as base bool break byte case catch char checked decimal default delegate continue doubl ...

  9. Oracle Fusion Applications (11.1.8) Media Pack and Oracle Application Development Framework 11g (11.1.1.7.2) for Microsoft Windows x64 (64-bit)

    Oracle Fusion Applications (11.1.8) Media Pack for Microsoft Windows x64 (64-bit) 重新搜索   常见问题    提示  ...

  10. 在Hdsi2.0 SQL的注入部分抓包分析语句

    在Hdsi2.0 SQL的注入部分抓包分析语句 恢复cmd ;insert tb1 exec master..xp_cmdshell''net user ''-- ;exec master.dbo.s ...