iOS - 关于瀑布流3.0的实现
只是说明实现瀑布流的方法, 以及自定义layout布局,其他多余事情本文不提。
先看项目框架:
1.ZJJCustomModel 类的内容
#import <Foundation/Foundation.h>
@interface ZJJCustomModel : NSObject
+ (NSArray *)customGetTheImagesArray;
@end
#import "ZJJCustomModel.h"
@implementation ZJJCustomModel
+ (NSArray *)customGetTheImagesArray {
// 0-30.jpg
NSMutableArray *arr = [NSMutableArrayarrayWithCapacity:0];
for (NSInteger i =0; i<31; i++) {
NSString *name = [NSStringstringWithFormat:@"%ld.jpg",i];
[arr addObject:name];
}
return arr;
}
@end
2.自定义cell(ZJJCustomCollectionCell)类
#import <UIKit/UIKit.h>
@interface ZJJCustomCollectionCell : UICollectionViewCell
- (id)initWithFrame:(CGRect)frame;
// 自定义 cell 的 label 和 image
@property (nonatomic,strong) UILabel *label;
@property (nonatomic,strong) UIImageView *imageView;
// 图片名字和文本名字
@property (nonatomic,copy) NSString *imageName;
@property (nonatomic,copy) NSString *labelName;
@end
#import "ZJJCustomCollectionCell.h"
@implementation ZJJCustomCollectionCell
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor colorWithRed:arc4random()%256/255.0 green:arc4random()%256/255.0 blue:arc4random()%256/255.0 alpha:1];
self.imageView = [[UIImageView alloc] init];
self.label = [[UILabel alloc] init];
[self addSubview:self.imageView];
[self addSubview:self.label];
}
return self;
}
- (void)setImageName:(NSString *)imageName {
self.imageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.imageView.image = [UIImage imageNamed:imageName];
}
- (void)setLabelName:(NSString *)labelName {
self.label.frame = CGRectMake(0, self.frame.size.height-30, self.frame.size.width, 30);
self.label.backgroundColor = [UIColor greenColor];
self.label.textColor = [UIColor redColor];
self.label.text = labelName;
self.label.textAlignment = NSTextAlignmentCenter;
}
@end
// 重用cell标识符
#define REUSE_CELL @"cell"
#import "ViewController.h"
#import "ZJJCustomLayout.h"
#import "ZJJCustomModel.h"
#import "ZJJCustomCollectionCell.h"
@interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegateFlowLayout> {
UICollectionView *_collect;
NSArray *_dataArray; // 数据源
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
[self arrayInfo];
}
#pragma mark - 基础配置
- (void)creatView {
ZJJCustomLayout *layout = [[ZJJCustomLayout alloc] init];
layout.itemCount = _dataArray.count;
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
_collect = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
_collect.backgroundColor = [UIColor whiteColor];
_collect.delegate = self;
_collect.dataSource = self;
[_collect registerClass:[ZJJCustomCollectionCell class] forCellWithReuseIdentifier:REUSE_CELL];
[self.view addSubview:_collect];
}
#pragma mark - 获取数据,填充数据源
- (void)arrayInfo {
_dataArray = [ZJJCustomModel customGetTheImagesArray];
[self creatView];
}
#pragma mark - collectionView 代理方法
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _dataArray.count;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ZJJCustomCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:REUSE_CELL forIndexPath:indexPath];
cell.imageName = _dataArray[indexPath.row];
cell.labelName = [NSString stringWithFormat:@"总价:%ld元",indexPath.row+1];
return cell;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"点击了第%ld个item",indexPath.row);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
#import <UIKit/UIKit.h>
@interface ZJJCustomLayout : UICollectionViewFlowLayout
@property (nonatomic, assign) NSInteger itemCount; //元素个数
@end
#define SCREEN_W [UIScreen mainScreen].bounds.size.width
#define SCREEN_H [UIScreen mainScreen].bounds.size.height
#import "ZJJCustomLayout.h"
@interface ZJJCustomLayout () {
float _itemW; // 元素宽度
float _itemH; // 元素高度
float _heightArray[3]; // 记录每列高度的数组,这里的瀑布流规定有三列
NSMutableArray *_attributesMArray; // 装有item属性的数组
}
@end
@implementation ZJJCustomLayout
- (void)prepareLayout {
[super prepareLayout];
// 这里假设有三列,给每列赋初始值(状态栏高度)
_heightArray[0] = 20.0f;
_heightArray[1] = 20.0f;
_heightArray[2] = 20.0f;
_attributesMArray = [NSMutableArray array];
[_attributesMArray removeAllObjects];
// 内外间隔是 10 ,可以设置每个元素的固定宽度
_itemW = (SCREEN_W-10*(1+3))/3;
for (NSInteger i = 0; i<_itemCount; i++) {
// 随机给高度
_itemH = arc4random()%50 + _itemW + 30;
// 每个元素的横纵坐标
float itemX = 0.0f;
float itemY = 0.0f;
/**
记录 当前元素应该放在哪一列
columnRecord = 0 , 1 , 2
分别表示应该放在 第 1 , 2 ,3 列
*/
int columnRecord = 0;
if (i == 0) {
columnRecord = 0;
}else if (i == 1) {
columnRecord = 1;
}else if (i == 2) {
columnRecord = 2;
}else {
// 找到最矮的
if (_heightArray[0] > _heightArray[1]) {
if (_heightArray[1] > _heightArray[2]) {
columnRecord = 2;
}else {
columnRecord = 1;
}
}else {
if (_heightArray[0] > _heightArray[2]) {
columnRecord = 2;
}else {
columnRecord = 0;
}
}
}
if (columnRecord == 0) {
itemX = 10;
itemY = _heightArray[0];
// 上下间隔 5 ,不要那么紧凑
_heightArray[0] += _itemH + 5;
}else if (columnRecord == 1) {
itemX = 10 + _itemW+10;
itemY = _heightArray[1];
_heightArray[1] += _itemH + 5;
}else {
itemX = (10+_itemW)*2+10;
itemY = _heightArray[2];
_heightArray[2] += _itemH + 5;
}
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = CGRectMake(itemX, itemY, _itemW, _itemH);
[_attributesMArray addObject:attributes];
}
}
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
return _attributesMArray;
}
- (CGSize)collectionViewContentSize {
float totalHeight = 0.0f;
if (_heightArray[0] > _heightArray[1]) {
totalHeight = MAX(_heightArray[0], _heightArray[2]);
}else {
totalHeight = MAX(_heightArray[1], _heightArray[2]);
}
return CGSizeMake(SCREEN_W, totalHeight);
}
@end