iOS 瀑布流的基本原理
/**
* 源代码链接
* 链接: 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 瀑布流的基本原理的更多相关文章
- IOS 瀑布流UICollectionView实现
IOS 瀑布流UICollectionView实现 在实现瀑布流之前先来看看瀑布流的雏形(此方法的雏形 UICollectionView) 对于UICollectionView我们有几点注意事项 它和 ...
- iOS 瀑布流之栅格布局
代码地址如下:http://www.demodashi.com/demo/14760.html 一 .效果预览 二.确定需求 由下面的需求示意图可知模块的最小单位是正方形,边长是屏幕宽除去边距间隔后的 ...
- iOS 瀑布流封装
代码地址如下:http://www.demodashi.com/demo/12284.html 一.效果预览 功能描述:WSLWaterFlowLayout 是在继承于UICollectionView ...
- IOS 瀑布流
本篇博客应该算的上CollectionView的高级应用了,从iOS开发之窥探UICollectionViewController(一)到今天的(五),可谓是由浅入深的窥探了一下UICollectio ...
- iOS瀑布流实现(Swift)
这段时间突然想到一个很久之前用到的知识-瀑布流,本来想用一个简单的方法,发现自己走入了歧途,最终只能狠下心来重写UICollectionViewFlowLayout.下面我将用两种方法实现瀑布流,以及 ...
- iOS 瀑布流的Demo
/** * 瀑布流Demo的主要代码,若想看完整的代码请到下面链接去下载 * * 链接: https://pan.baidu.com/s/1slByAHB 密码: r3q6 */ #import &l ...
- ios 瀑布流的那些事情
转载: 屎壳郎情调-成长日记 首先要知道:瀑布流的核心就是要获取到图片的长宽 网上的很多例子都是加载本地图片的 对于新手而言 改成加载网络图片的确是有点压力的 因为本地的图片 我们是很容易就能获取到 ...
- ios瀑布流
http://blog.csdn.net/shenjx1225/article/details/9037631
- iOS开发笔记15:地图坐标转换那些事、block引用循环/weak–strong dance、UICollectionviewLayout及瀑布流、图层混合
1.地图坐标转换那些事 (1)投影坐标系与地理坐标系 地理坐标系使用三维球面来定义地球上的位置,单位即经纬度.但经纬度无法精确测量距离戒面积,也难以在平面地图戒计算机屏幕上显示数据.通过投影的方式可以 ...
随机推荐
- NSQ:分布式消息队列学习记录
参考资料: NSQ:分布式的实时消息平台 初识NSQ分布式实时消息架构 深入NSQ之旅 nsq topic和channel的区别
- PHP 错误与异常 笔记与总结(9)自定义错误处理器
自定义错误处理器更加智能. <?php class myErrorHandler{ //$message:错误信息 //$filename:错误文件名 //$line:错误行号 //$vars: ...
- adId、idfv
//广告标示符,适用于对外:例如广告推广,换量等跨应用的用户追踪等. NSString *adId = [[[ASIdentifierManager sharedManager] advertisin ...
- mysql IN 比等价的OR写法效率更高
- PHP 用QueryList抓取网页内容
http://www.cnblogs.com/wb145230/p/4716403.html 之前抓取网页数据都是用Java Jsoup,前几天听说用PHP抓更方便,今天就简单研究了一下,主要是用Qu ...
- ArcGIS for Sever 10.1 服务迁移与恢复
=== 声明:以下内容本是自己写给单位内部同事的参考手册,但是被传到百度文库中.陆续有用户就这方面的问题,通过电话,邮件等方式联系我.首先,感到荣幸.其次是,由于本人当时测试和编写的时候,由于仓促,可 ...
- 运行EFDC出现这样的错误:forrt1:severe<157>:Program Exception-access violation
经过检查是由于TQSER出现读写错误,原来我的数据输入文件的时间是427天,后来延长到639,但其中有一个点的时间仍然维持在427.故此出现这个错误.EFDC是用Fortran编译的,通过debug才 ...
- HDFS中高可用性HA的讲解
HDFS Using QJM HA使用的是分布式的日志管理方式 一:概述 1.背景 如果namenode出现问题,整个HDFS集群将不能使用. 是不是可以有两个namenode呢 一个为对外服务-&g ...
- WPF绑定方式
绑定到其它元素 <Grid> <StackPanel> <TextBox x:Name="textbox1" /> ...
- CSS弹性盒布局
<html> <head> <meta charset="utf-8"/> <title></title> <st ...
