//
// AppDelegate.h
// UI21_WaterFlowLayout
//
// Created by l on 15/10/5.
// Copyright (c) 2015年 . All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
//
// AppDelegate.m
// UI21_WaterFlowLayout
//
// Created by l on 15/10/5.
// Copyright (c) 2015年 . All rights reserved.
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
@end
///////////////////////////////////////////////////////////////////
//
// ViewController.h
// UI21_WaterFlowLayout
//
// Created by l on 15/10/5.
// Copyright (c) 2015年 . All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
//
// ViewController.m
// UI21_WaterFlowLayout
//
// Created by l on 15/10/5.
// Copyright (c) 2015年 . All rights reserved.
//
#import "ViewController.h"
#import "WaterFlowLayout.h"
#import "ImageCell.h"
#import "Model.h"
#import "UIImageView+WebCache.h" //sd分类.导入第三方类库.
@interface ViewController ()<WaterFlowLayoutDelegate, UICollectionViewDelegate, UICollectionViewDataSource>
@property (nonatomic, strong) NSMutableArray *dataArray; //存放model的数组
@end
@implementation ViewController
//本地解析方法
- (void)setData{
//1.获取文件路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"json"];
//2.转换为data
NSData *data = [NSData dataWithContentsOfFile:filePath];
//3.json解析
NSArray *rootArray = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.dataArray = [NSMutableArray array];
for (NSDictionary *dic in rootArray) {
Model *model = [[Model alloc] init];
[model setValuesForKeysWithDictionary:dic];
[_dataArray addObject:model];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
//进行本地解析
[self setData];
//1.创建waterFlowLayout
WaterFlowLayout *waterFlowLayout = [[WaterFlowLayout alloc] init];
//列数
waterFlowLayout.numberOfColumn = 3;
//间距
waterFlowLayout.insertItemSpacing = 10;
//边距
waterFlowLayout.sectionInsets = UIEdgeInsetsMake(20, 20, 20, 20);
//itemSize
CGFloat width = ([UIScreen mainScreen].bounds.size.width - 2 * 20 - 10 * 2) / 3;
waterFlowLayout.itemSize = CGSizeMake(width, width);
//设置代理
waterFlowLayout.delegate = self;
//2.创建collectionView
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:waterFlowLayout];
collectionView.delegate = self;
collectionView.dataSource = self;
//注册单元格
[collectionView registerClass:[ImageCell class] forCellWithReuseIdentifier:@"cell"];
[self.view addSubview:collectionView];
}
#pragma mark----------dataSource--------
//单元元素数
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _dataArray.count;
}
//加载单元格
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
//1.取出
ImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
//2.赋值
//imageView赋值image
//model
Model *model = _dataArray[indexPath.item];
//设置图片
[cell.myImageView sd_setImageWithURL:[NSURL URLWithString:model.thumbURL]];
//3.返回
return cell;
}
#pragma mark----------瀑布流代理方法---------
- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath {
//图片缩放前的宽高比和缩放后的 宽高比一样,则不失真
/*
原本宽度 缩放宽度
______ = ______
原本高度 缩放高度
缩放宽度指定,获取缩放后的高度
原本高度
缩放高度 = 缩放宽度 * ______
原本宽度
height = width * model.height / model.width
*/
//model
Model *model = _dataArray[indexPath.item];
CGFloat width = ([UIScreen mainScreen].bounds.size.width - 2 * 20 - 10 * 2) / 3;
CGFloat height = width * model.height / model.width;
return height;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
/////////////////////////////////////////////////////////////////////
//
// WaterFlowLayout.h
// UI21_WaterFlowLayout
//
// Created by l on 15/10/5.
// Copyright (c) 2015年 . All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol WaterFlowLayoutDelegate <NSObject>
//协议方法,用来获取item的高度
- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath;
@end
@interface WaterFlowLayout : UICollectionViewLayout
//瀑布流布局
//瀑布流布局需要指定的布局因素 itemSize , 边距 sectionInsets , 间距 insertItemSpacing , 列数 numberOfColumn , 代理 delegate
//存储列长度的数组heightColumns , items 的属性(宽, 高, x, y)
@property (nonatomic, assign) CGSize itemSize; //itemSize
@property (nonatomic, assign) CGFloat insertItemSpacing; //间距
@property (nonatomic, assign) UIEdgeInsets sectionInsets; //边距
@property (nonatomic, assign) NSInteger numberOfColumn; //列数
@property (nonatomic, assign) id<WaterFlowLayoutDelegate> delegate; //代理
@end
//
// WaterFlowLayout.m
// UI21_WaterFlowLayout
//
// Created by l on 15/10/5.
// Copyright (c) 2015年 . All rights reserved.
//
#import "WaterFlowLayout.h"
@interface WaterFlowLayout ()
//分区里面元素的个数
@property (nonatomic, assign) NSInteger numberOfItems;
//存储列高度的数组 columnHeights
@property (nonatomic, strong) NSMutableArray *columnHeights;
//存储item属性的数组,itemAttributes
@property (nonatomic, strong) NSMutableArray *itemAttributes;
//获取最长列的下标
- (NSInteger)indexForLongestColumn;
//获取最短列的下标
- (NSInteger)indexForShortestColumn;
@end
@implementation WaterFlowLayout
//懒加载 给数据容器开辟空间.
//何为懒加载? 没有写在init和viewDidLoad里面,而是写在了get方法里面,只有当用到该值的时候,才加载数据.
//优点:节省了内存开辟.
- (NSMutableArray *)columnHeights {
if (!_columnHeights) {
self.columnHeights = [NSMutableArray array];
}
return _columnHeights;
}
- (NSMutableArray *)itemAttributes {
if (!_itemAttributes) {
self.itemAttributes = [NSMutableArray array];
}
return _itemAttributes;
}
//求最长列的下标
- (NSInteger)indexForLongestColumn {
//最长列下标
NSInteger longestIndex = 0;
//最长列高度
NSInteger longestHeight = 0; //设置为0,确保可以跟每一列进行比较.
//循环遍历,数组中每个元素,进行比较,找出最长列下标.
for (int i = 0; i < _columnHeights.count; i++) {
//当前i元素的高度
CGFloat currentHeight = [_columnHeights[i] floatValue];
//比较
if (currentHeight > longestHeight) {
longestHeight = currentHeight;
longestIndex = i;
}
}
return longestIndex;
}
//求最小列下标
- (NSInteger)indexForShortestColumn {
//最小列下标
NSInteger shortestIndex = 0;
//最小列高度
CGFloat shortestHeight = CGFLOAT_MAX; // 设置为浮点数最大值,确保可以进行比较
//遍历,找出最小值下标
for (int i = 0; i < _columnHeights.count; i++) {
//当前列i的高度
CGFloat currentHeight = [_columnHeights[i] floatValue];
if (currentHeight < shortestHeight) {
shortestHeight = currentHeight;
shortestIndex = i;
}
}
return shortestIndex;
}
//重写准备布局方法
- (void)prepareLayout {
//必须调用 super prepareLayout
[super prepareLayout];
//1.给存储列高度的数组,附上top值
for (int i = 0; i < _numberOfColumn; i++) {
//类型转换, 把CGFloat转换为对象类型
self.columnHeights[i] = @(self.sectionInsets.top);
}
//2.获取分区中元素的个数
self.numberOfItems = [self.collectionView numberOfItemsInSection:0];
//3.给每一个item设置 frame和indexPath
for (int i = 0; i < _numberOfItems; i++) {
//(1)当前item的indexPath
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
//(2)获取item的layoutAttributes
UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//(3)给layoutAttributes的frame赋值
//最小列下标
NSInteger shortestIndex = [self indexForShortestColumn];
//最小列高度
CGFloat shortestHeight = [_columnHeights[shortestIndex] floatValue];
//元素的x值 = 左边距left + (item宽度 + 水平间距) * 最小列下标(0 , 1, 2, ......)
//itemX
CGFloat itemX = _sectionInsets.left + (_itemSize.width + _insertItemSpacing) * shortestIndex;
//itemY
CGFloat itemY = shortestHeight + _insertItemSpacing;
//itemWidth
CGFloat itemWidth = _itemSize.width;
//itemHeight
//itemHeight 由代理执行的协议方法来获取,协议方法有返回值,为item高度.
CGFloat itemHeight = 0; //定义
if (_delegate != nil && [_delegate respondsToSelector:@selector(heightForItemIndexPath:)]) {
itemHeight = [_delegate heightForItemIndexPath:indexPath];
}
//给layoutAttributes的frame赋值.
layoutAttributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);
//4.把赋值好的layoutAttributes存放到数组里面.
[self.itemAttributes addObject:layoutAttributes];
//5.更新最短列的高度
//高度 = itemY + itemHeight
self.columnHeights[shortestIndex] = @(itemY + itemHeight);
}
}
//重写collectionViewContentSize方法, 确定最终高度.
- (CGSize)collectionViewContentSize {
//获取最长列下标
NSInteger longestIndex = [self indexForLongestColumn];
//获取高度
CGFloat longestHeight = [self.columnHeights[longestIndex] floatValue];
//获取当前的contentSize frame.size
CGSize contentSize = self.collectionView.frame.size;
//更改contentSize的高度
contentSize.height = longestHeight;
//返回
return contentSize;
}
//重写 返回每一个元素的布局属性
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
//返回存储每一个单元格frame的数组.
return self.itemAttributes;
}
@end
////////////////////////////////////////////////////////////////////
//
// ImageCell.h
// UI21_瀑布流
//
// Created by on 15/10/4.
// Copyright © 2015年 littledogboy. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ImageCell : UICollectionViewCell
@property (nonatomic,strong)UIImageView *myImageView;
@end
//
// ImageCell.m
// UI21_瀑布流
//
// Created by on 15/10/4.
// Copyright © 2015年 littledogboy. All rights reserved.
//
#import "ImageCell.h"
@implementation ImageCell
// 重写initWithFrame 方法,添加内部控件
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.myImageView = [[UIImageView alloc] initWithFrame:self.bounds];
[self.contentView addSubview:_myImageView];
}
return self;
}
// 重写布局子视图方法, 给
- (void)layoutSubviews
{
[super layoutSubviews];
self.myImageView.frame = self.bounds;
}
@end
////////////////////////////////////////////////////////////////////
//
// Model.h
// UI21_瀑布流
//
// Created by on 15/10/5.
// Copyright © 2015年 littledogboy. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Model : NSObject
@property(nonatomic, copy) NSString *thumbURL;
@property(nonatomic, assign) CGFloat width;
@property(nonatomic, assign) CGFloat height;
@end
//
// Model.m
// UI21_瀑布流
//
// Created by on 15/10/5.
// Copyright © 2015年 littledogboy. All rights reserved.
//
#import "Model.h"
@implementation Model
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{
}
-(void)setValue:(id)value forKey:(NSString *)key
{
[super setValue:value forKey:key];
if ([key isEqualToString:@"width"]) {
self.width = [value floatValue]; // 主意要转化为 floatValue 类型
}
if ([key isEqualToString:@"height"]) {
self.height = [value floatValue];
}
}
@end
iOS编程------集合视图之瀑布流WaterFlowLayout
最新推荐文章于 2022-09-04 18:33:32 发布
7888

被折叠的 条评论
为什么被折叠?



