/**
* 源代码链接
* 链接: https://pan.baidu.com/s/1nvLamEX 密码: kya5
*/
#import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end
#import "AppDelegate.h"
#import "RootViewController.h"
@interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor]; self.window.rootViewController = [[RootViewController alloc] init]; [self.window makeKeyAndVisible];
return YES;
} @end
#import <UIKit/UIKit.h>

@interface RootViewController : UIViewController

@end
#import "RootViewController.h"
#import "LFWaterfallLayout.h"
@interface RootViewController ()<UICollectionViewDataSource,LFWaterfallLayoutDelegate> @end @implementation RootViewController static NSString *const identifier = @"waterfall"; - (void)viewDidLoad {
[super viewDidLoad]; // 创建布局
LFWaterfallLayout *layout = [[LFWaterfallLayout alloc] init];
layout.delegate = self;
// 创建collecView
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
collectionView.dataSource = self;
[self.view addSubview:collectionView];
// 注册
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:identifier];
} #pragma mark -- UICollectionViewDataSource --
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return ;
} - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; cell.backgroundColor = [UIColor orangeColor]; NSInteger tag = ;
UILabel *label = (UILabel *)[cell viewWithTag:tag];
if (!label) {
label = [[UILabel alloc] init];
label.tag = tag;
label.frame = cell.bounds;
[cell.contentView addSubview:label];
} return cell;
}
#pragma mark -- LFWaterfallLayoutDelegate --
- (CGFloat)waterflowLayout:(LFWaterfallLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth{
return + arc4random_uniform();
}
//
//- (CGFloat)columnCountInWaterflowLayout:(LFWaterfallLayout *)waterflowLayou{
// return 2;
//}
//- (CGFloat)columnMarginInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout{
// return 20;
//}
//- (CGFloat)rowMarginInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout{
// return 20;
//}
//- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout{
// return UIEdgeInsetsMake(20, 20, 20, 20);
//} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} @end
#import <UIKit/UIKit.h>
@class LFWaterfallLayout;
/**
* 代理传值
*/
@protocol LFWaterfallLayoutDelegate <NSObject> @required
- (CGFloat)waterflowLayout:(LFWaterfallLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth; @optional
/**
* 设置瀑布流的列数
*/
- (CGFloat)columnCountInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout;
/**
* 设置瀑布流列的间距
*/
- (CGFloat)columnMarginInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout;
/**
* 设置瀑布流行的间距
*/
- (CGFloat)rowMarginInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout;
/**
* 设置瀑布流边缘(四周)的间隙
*/
- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(LFWaterfallLayout *)waterflowLayout;
@end @interface LFWaterfallLayout : UICollectionViewLayout @property (nonatomic , weak) id<LFWaterfallLayoutDelegate> delegate; @end
#import "LFWaterfallLayout.h"

static const NSInteger LFDefaultColumnCount = ;//默认的列数
static const CGFloat LFDefaultColumnMargin = ;//每一列之间的间距
static const CGFloat LFDefaultRowMargin = ;//每一行之间的间距
static const UIEdgeInsets LFDefaultEdgeInsets = {,,,};//边缘间距 @interface LFWaterfallLayout ()
/**
* 存放所有cell的布局属性
*/
@property (nonatomic , strong) NSMutableArray *attrsArray;
/**
* 存放所有列的当前高度
*/
@property (nonatomic , strong) NSMutableArray *columnHeights; - (CGFloat)rowMargin;
- (CGFloat)columnMargin;
- (NSInteger)columnCount;
- (UIEdgeInsets)endgeInsets; @end @implementation LFWaterfallLayout #pragma mark -- 数据处理 --
- (CGFloat)rowMargin{
if ([self.delegate respondsToSelector:@selector(rowMarginInWaterflowLayout:)]) {
return [self.delegate rowMarginInWaterflowLayout:self];
}else{
return LFDefaultRowMargin;
}
} - (CGFloat)columnMargin{
if ([self.delegate respondsToSelector:@selector(columnMarginInWaterflowLayout:)]) {
return [self.delegate columnMarginInWaterflowLayout:self];
}else{
return LFDefaultColumnMargin;
}
} - (UIEdgeInsets)endgeInsets{
if ([self.delegate respondsToSelector:@selector(edgeInsetsInWaterflowLayout:)]) {
return [self.delegate edgeInsetsInWaterflowLayout:self];
}else{
return LFDefaultEdgeInsets;
} } - (NSInteger)columnCount{
if ([self.delegate respondsToSelector:@selector(columnCountInWaterflowLayout:)]) {
return [self.delegate columnCountInWaterflowLayout:self];
}else{
return LFDefaultColumnCount;
}
} - (NSMutableArray *)attrsArray{
if (!_attrsArray) {
_attrsArray = [NSMutableArray array];
}
return _attrsArray;
} - (NSMutableArray *)columnHeights{
if (!_columnHeights) {
_columnHeights = [NSMutableArray array];
}
return _columnHeights;
} /**
* 初始化
*/
- (void)prepareLayout{
[super prepareLayout];
// 清除以前计算的所有高度
[self.columnHeights removeAllObjects];
for (NSInteger i = ; i < self.columnCount; i++) {
[self.columnHeights addObject:@(self.endgeInsets.top)];
} // 清除之前所有的布局属性
[self.attrsArray removeAllObjects]; // 开始创建每一个cell对应的布局属性
NSInteger count = [self.collectionView numberOfItemsInSection:]; for (NSInteger i = ;i < count;i++) {
// 创建位置
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:]; // 获取indexPath位置对应cell的属性
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath]; [self.attrsArray addObject:attributes];
}
} /**
* 决定cell的布局
*/
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{ return self.attrsArray;
} /**
* 返回indexPath位置cell对应的布局属性
*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
// 创建布局属性
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//collectionView的宽度
CGFloat collectionViewWidth = self.collectionView.frame.size.width; // 找出高度最短的那一列
NSInteger shortestColumn = ;
// 找出最小高度
CGFloat minColumnHeight = [self.columnHeights[] doubleValue];
for (NSInteger i = ; i < self.columnCount; i++) {
// 取出第i列的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
// 比较大小
if (minColumnHeight > columnHeight) {
minColumnHeight = columnHeight;
shortestColumn = i;
}
}
// 宽度
CGFloat width = (collectionViewWidth - self.endgeInsets.left - self.endgeInsets.right - (self.columnCount - ) *self.columnMargin) / self.columnCount;
// x坐标
CGFloat x = self.endgeInsets.left + shortestColumn * (width + self.columnMargin);
// y坐标
CGFloat y = minColumnHeight;
if (y != self.endgeInsets.top) {
y += self.rowMargin;
} // 高度
CGFloat height = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:width];
//设置布局属性的frame
attributes.frame = CGRectMake(x,y, width, height); // 更新高度
self.columnHeights[shortestColumn] = @(CGRectGetMaxY(attributes.frame)); return attributes;
} - (CGSize)collectionViewContentSize{ // 找出最大高度
CGFloat maxColumnHeight = [self.columnHeights[] doubleValue];
for (NSInteger i = ; i < self.columnCount; i++) {
// 取出第i列的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
// 比较大小
if (maxColumnHeight < columnHeight) {
maxColumnHeight = columnHeight;
}
}
return CGSizeMake(, maxColumnHeight + self.endgeInsets.bottom);
} @end

iOS 瀑布流的基本原理的更多相关文章

  1. IOS 瀑布流UICollectionView实现

    IOS 瀑布流UICollectionView实现 在实现瀑布流之前先来看看瀑布流的雏形(此方法的雏形 UICollectionView) 对于UICollectionView我们有几点注意事项 它和 ...

  2. iOS 瀑布流之栅格布局

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

  3. iOS 瀑布流封装

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

  4. IOS 瀑布流

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

  5. iOS瀑布流实现(Swift)

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

  6. iOS 瀑布流的Demo

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

  7. ios 瀑布流的那些事情

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

  8. ios瀑布流

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

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

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

随机推荐

  1. oracle sql日期比较

    oracle sql日期比较:在今天之前: select * from up_date where update < to_date('2007-09-07 00:00:00','yyyy-mm ...

  2. HTTP 笔记与总结(2 )HTTP 协议的(请求行的)请求方法 及 (响应行的)状态码

    (请求行的)请求方法 包括: GET,POST,HEAD,PUT,TRACE,DELETE,OPTIONS 注意:这些请求方法虽然是 HTTP 协议规定的,但是 Web Server 未必允许或支持这 ...

  3. Python常用函数笔记

    1.lambda lambda其实就是一条语句,lambda(x):body.x是lambda函数的参数,参数可以有任意多个(包括可选参数);body是函数体,只能是一个表达式,并且直接返回该表达式的 ...

  4. 【翻译】口袋妖怪X/Y 制作技法

    口袋妖怪X/Y [口袋妖怪]系列最终的全3D化     再现图像风格的制作技法   完成系列最初的全3D化的本作,在手掌游戏机的性能和容量的限制中,把杉森建氏的公式设定图风格用Toon Shading ...

  5. placeholder属性实现text标签默认值提示用户

    <input type="text" class="searchTxt" id=this.id+"-searchTxt" placeh ...

  6. Python实用工具包Scrapy安装教程

       对于想用每个想用Python开发网络爬虫的开发者来说,Scrapy无疑是一个极好的开源工具.今天安装之后觉得Scrapy的安装确实不易啊.所以在此博文一篇,往后来着少走弯路. 废话不多说了,如果 ...

  7. delimiter

    http://www.mysqltutorial.org/getting-started-with-mysql-stored-procedures.aspx The first command is  ...

  8. href="#"和javasrcript:void(0)的区别

    当我们需要一个空链接时,通常有两种方法: <a href="#">这个一个空链接</a> 和 <a href="javascript:voi ...

  9. php session 跨页失效问题

    原因是session.savepath 目录不存在或者没有读写权限

  10. PHP 加密 和 解密 方法

    关于Discuz的加密解密函数,相信大家都有所了解,该authcode函数可以说是对PHP界作出了重大的贡献,真的发觉discuz这个函数写的太精彩啦. 研究了一下这个算法,总的来说可以归纳为以下三点 ...