您的位置:首页 > 移动开发 > IOS开发

iOS 瀑布流的基本原理

2016-08-31 16:46 337 查看


/**
* 源代码链接
* 链接: 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 50;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

cell.backgroundColor = [UIColor orangeColor];

NSInteger tag = 10;
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 50 + arc4random_uniform(120);
}
//
//- (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 = 3;//默认的列数
static const CGFloat LFDefaultColumnMargin = 10;//每一列之间的间距
static const CGFloat LFDefaultRowMargin = 10;//每一行之间的间距
static const UIEdgeInsets LFDefaultEdgeInsets = {10,10,10,10};//边缘间距

@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 = 0; i < self.columnCount; i++) {
[self.columnHeights addObject:@(self.endgeInsets.top)];
}

// 清除之前所有的布局属性
[self.attrsArray removeAllObjects];

// 开始创建每一个cell对应的布局属性
NSInteger count = [self.collectionView numberOfItemsInSection:0];

for (NSInteger i = 0 ;i < count;i++) {
// 创建位置
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

// 获取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 = 0;
// 找出最小高度
CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
for (NSInteger i = 1 ; 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 - 1) *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[0] doubleValue];
for (NSInteger i = 1 ; i < self.columnCount; i++) {
// 取出第i列的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
// 比较大小
if (maxColumnHeight < columnHeight) {
maxColumnHeight = columnHeight;
}
}
return CGSizeMake(0, maxColumnHeight + self.endgeInsets.bottom);
}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: