一. UICollectionView介绍
- UICollectionView和UITableView一样是继承于UIScrollView的控件,但是UICollectionView比UITableView更为复杂。
- UICollectionView也有两个代理:UICollectionViewDelegate、UICollectionViewDataSource。
- UICollectionView创建的时候必须要用initWithFrame : collectionViewLayout传入一个布局。
- 简单的布局可以传入UICollectionViewFlowLayout这个系统的类,它是UICollectionViewLayout的子类。
- 不能直接使用UICollectionViewLayout这个布局对象(必须用他的子类)。
- 更复杂的布局需要自己写UICollectionViewLayout的子类(如瀑布流)。
二. UICollectionView的简单使用
UICollectionView的使用和UITableView的使用类似,都是遵守代理和数据源,并实现相应的方法。不同的是UICollectionView还要传入一个布局,如果是简单的布局,传入系统的UICollectionViewFlowLayout就可以了。
如果布局的大小都是固定的,我们直接使用UICollectionViewFlowLayout的属性指定大小就好了,如下:
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
//item的size
flowLayout.itemSize = CGSizeMake(self.w_h, self.w_h + 32 + 32);
//section的内边距,设置之后会在内边距里面布局
flowLayout.sectionInset = UIEdgeInsetsMake(10, 15, 10, 15);
//item的最小行间距
flowLayout.minimumLineSpacing = 14;
//item的最小列间距
flowLayout.minimumInteritemSpacing = 10;
如果布局的大小不固定,那么我们遵守UICollectionViewDelegateFlowLayout协议,并实现协议方法就行了,如下:
//item的size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(self.w_h, self.w_h + 32 + 32);
}
//section的内边距,设置之后会在内边距里面布局
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(10, 15, 10, 15);
}
//item最小行间距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
//item最小列间距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
然后创建collectionView的时候传入布局,如下,其他的都和UITableView的使用是一样的了。
- (UICollectionView *)collectionView {
if (!_collectionView) {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
// flowLayout.itemSize = CGSizeMake(self.w_h, self.w_h + 32 + 32);
// flowLayout.sectionInset = UIEdgeInsetsMake(10, 15, 10, 15);
// flowLayout.minimumLineSpacing = 14;
// flowLayout.minimumInteritemSpacing = 10;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight) collectionViewLayout:flowLayout];
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.dataSource = self;
_collectionView.delegate = self;
_collectionView.showsVerticalScrollIndicator = NO;
}
return _collectionView;
}
注意:
- 如果布局大小固定,可以直接通过设置UICollectionViewFlowLayout的属性指定大小。
- 如果布局大小不固定,必须遵守UICollectionViewDelegateFlowLayout协议,然后实现相应的布局方法(绝对不能忘记)。
- 如果通过属性设置了布局又实现了UICollectionViewDelegateFlowLayout协议的布局方法,以协议方法的布局优先。
- UICollectionViewDataSource是提供数据源的,比如多少行,每行多少item,每行的item什么样,每行的头尾视图是什么。UICollectionViewDelegate是代理回调,比如点击了某个item。 UICollectionViewDelegateFlowLayout是提供布局的。
所以一般使用UICollectionView一定不要忘了遵守这三个协议。
三. 自定义UICollectionViewLayout
1. 瀑布流效果
上面我们说了, 如果更复杂的布局需要自定义UICollectionViewLayout, 现在我们就自定义一个类继承于UICollectionViewLayout, 来实现瀑布流效果。
先看效果图:自定义HMWaterfallLayout继承于UICollectionViewLayout, 代码如下:
HMWaterfallLayout.h
#import <UIKit/UIKit.h>
@class HMWaterfallLayout;
@protocol HMWaterfallLayoutDelegate <NSObject>
//通过宽度和indexpath 返回当前位置的高度
- (CGFloat)waterflowLayout:(HMWaterfallLayout *)waterflowLayout heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath *)indexPath;
@end
@interface HMWaterfallLayout : UICollectionViewLayout
//距离边上多少距离
@property (nonatomic, assign) UIEdgeInsets sectionInset;
/** 每一列之间的间距 */
@property (nonatomic, assign) CGFloat columnMargin;
/** 每一行之间的间距 */
@property (nonatomic, assign) CGFloat rowMargin;
/** 显示多少列 */
@property (nonatomic, assign) int columnsCount;
//代理
@property (nonatomic, weak) id<HMWaterfallLayoutDelegate> delegate;
@end
HMWaterfallLayout.m
#import "HMWaterfallLayout.h"
//static const CGFloat HMColumnMargin = 10;
//static const CGFloat HMRowMargin = HMColumnMargin;
@interface HMWaterfallLayout();
/** 这个字典用来存储每一列最大的Y值(每一列的高度) */
@property (nonatomic, strong) NSMutableDictionary *maxYDict;
/** 存放所有的布局属性 */
@property (nonatomic, strong) NSMutableArray *attrsArray;
@end
@implementation HMWaterfallLayout
- (NSMutableDictionary *)maxYDict
{
if (!_maxYDict) {
self.maxYDict = [[NSMutableDictionary alloc] init];
}
return _maxYDict;
}
- (NSMutableArray *)attrsArray
{
if (!_attrsArray) {
self.attrsArray = [[NSMutableArray alloc] init];
}
return _attrsArray;
}
- (instancetype)init
{
if (self = [super init]) {
self.columnMargin = 10;
self.rowMargin = 10;
self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
self.columnsCount = 3;
}
return self;
}
//发生滚动的时候改变bounds
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
NSLog(@"shouldInvalidateLayoutForBoundsChange");
return YES;
}
/**
* 每次布局之前的准备
*/
- (void)prepareLayout
{
[super prepareLayout];
NSLog(@"prepareLayout");
// 1.清空最大的Y值
for (int i = 0; i<self.columnsCount; i++) {
NSString *column = [NSString stringWithFormat:@"%d", I];
self.maxYDict[column] = @(self.sectionInset.top);
}
// 2.计算所有cell的属性
[self.attrsArray removeAllObjects];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i<count; i++) {
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[self.attrsArray addObject:attrs];
}
}
/**
* 返回所有的尺寸
*/
- (CGSize)collectionViewContentSize
{
NSLog(@"collectionViewContentSize");
__block NSString *maxColumn = @"0";
//找出最大的那一列
[self.maxYDict enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) {
if ([maxY floatValue] > [self.maxYDict[maxColumn] floatValue]) {
maxColumn = column;
}
}];
return CGSizeMake(0, [self.maxYDict[maxColumn] floatValue] + self.sectionInset.bottom);
}
/**
* 返回indexPath这个位置Item的布局属性,每次要显示一个新的cell的时候就要调用
找到最短的那一列,在这个最短的那一列后面返回一个attribute
*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"layoutAttributesForItemAtIndexPath");
// 假设最短的那一列的第0列
__block NSString *minColumn = @"0";
// 找出最短的那一列
[self.maxYDict enumerateKeysAndObjectsUsingBlock:^(NSString *column, NSNumber *maxY, BOOL *stop) {
if ([maxY floatValue] < [self.maxYDict[minColumn] floatValue]) {
minColumn = column;
}
}];
// 计算尺寸
CGFloat width = (self.collectionView.frame.size.width - self.sectionInset.left - self.sectionInset.right - (self.columnsCount - 1) * self.columnMargin)/self.columnsCount;
CGFloat height = [self.delegate waterflowLayout:self heightForWidth:width atIndexPath:indexPath];
// 计算位置
CGFloat x = self.sectionInset.left + (width + self.columnMargin) * [minColumn intValue];
CGFloat y = [self.maxYDict[minColumn] floatValue] + self.rowMargin;
// 更新这一列的最大Y值
self.maxYDict[minColumn] = @(y + height);
// 创建属性
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.frame = CGRectMake(x, y, width, height);
return attrs;
}
/**
* 返回rect范围内的布局属性
*/
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSLog(@"layoutAttributesForElementsInRect");
return self.attrsArray;
}
@end
在ViewController里面遵守代理就可以直接使用了, model和view里面的代码太简单, 就直接省略了, 代码如下:
#import "HMWaterViewController.h"
#import "HMWaterfallLayout.h"
#import "MJExtension.h"
#import "HMShop.h"
#import "HMShopCell.h"
#import "MJRefresh.h"
@interface HMWaterViewController () <UICollectionViewDataSource, UICollectionViewDelegate, HMWaterfallLayoutDelegate>
@property (nonatomic, weak) UICollectionView *collectionView;
@property (nonatomic, strong) NSMutableArray *shops;
@end
@implementation HMWaterViewController
- (NSMutableArray *)shops
{
if (_shops == nil) {
self.shops = [NSMutableArray array];
}
return _shops;
}
static NSString *const ID = @"shop";
- (void)viewDidLoad {
[super viewDidLoad];
// 1.初始化数据
NSArray *shopArray = [HMShop objectArrayWithFilename:@"1.plist"];
[self.shops addObjectsFromArray:shopArray];
HMWaterfallLayout *layout = [[HMWaterfallLayout alloc] init];
layout.delegate = self;
// layout.sectionInset = UIEdgeInsetsMake(100, 20, 40, 30);
// layout.columnMargin = 20;
// layout.rowMargin = 30;
// layout.columnsCount = 4;
// 2.创建UICollectionView
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
collectionView.backgroundColor = [UIColor whiteColor];
collectionView.dataSource = self;
collectionView.delegate = self;
[collectionView registerNib:[UINib nibWithNibName:@"HMShopCell" bundle:nil] forCellWithReuseIdentifier:ID];
[self.view addSubview:collectionView];
self.collectionView = collectionView;
// 3.增加刷新控件
[self.collectionView addFooterWithTarget:self action:@selector(loadMoreShops)];
}
- (void)loadMoreShops
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSArray *shopArray = [HMShop objectArrayWithFilename:@"1.plist"];
[self.shops addObjectsFromArray:shopArray];
[self.collectionView reloadData];
[self.collectionView footerEndRefreshing];
});
}
#pragma mark - <HMWaterfallLayoutDelegate>
- (CGFloat)waterflowLayout:(HMWaterfallLayout *)waterflowLayout heightForWidth:(CGFloat)width atIndexPath:(NSIndexPath *)indexPath
{
HMShop *shop = self.shops[indexPath.item];
return shop.h / shop.w * width;
}
#pragma mark - <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.shops.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
HMShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
cell.shop = self.shops[indexPath.item];
return cell;
}
@end
运行代码, 就实现了上面的瀑布流效果。
2. 相册浏览效果
先看效果图:自定义HMLineLayout继承于UICollectionViewLayout, 代码如下:
HMLineLayout.h文件
#import <UIKit/UIKit.h>
@interface HMLineLayout : UICollectionViewLayout
@end
HMLineLayout.m文件
#import "HMLineLayout.h"
static const CGFloat HMItemWH = 100;
@implementation HMLineLayout
- (instancetype)init
{
if (self = [super init]) {
}
return self;
}
/**
* 只要显示的边界发生改变就重新布局:
内部会重新调用prepareLayout和layoutAttributesForElementsInRect方法获得所有cell的布局属性
*/
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
/**
停止滚动的时候调用
* 用来设置collectionView停止滚动那一刻的位置
*
* @param proposedContentOffset 原本collectionView停止滚动那一刻的位置
* @param velocity 滚动速度
*/
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
// 1.计算出scrollView最后会停留的范围
CGRect lastRect;
lastRect.origin = proposedContentOffset;
lastRect.size = self.collectionView.frame.size;
// 计算屏幕最中间的x
CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
// 2.取出这个范围内的所有属性
NSArray *array = [self layoutAttributesForElementsInRect:lastRect];
// 3.遍历所有属性
CGFloat adjustOffsetX = MAXFLOAT;
for (UICollectionViewLayoutAttributes *attrs in array) {
if (ABS(attrs.center.x - centerX) < ABS(adjustOffsetX)) {
adjustOffsetX = attrs.center.x - centerX;
}
}
return CGPointMake(proposedContentOffset.x + adjustOffsetX, proposedContentOffset.y);
}
/**
* 一些初始化工作最好在这里实现
*/
- (void)prepareLayout
{
[super prepareLayout];
// 每个cell的尺寸
self.itemSize = CGSizeMake(HMItemWH, HMItemWH);
CGFloat inset = (self.collectionView.frame.size.width - HMItemWH) * 0.5;
self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
// 设置水平滚动
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.minimumLineSpacing = HMItemWH * 0.7;
// 每一个cell(item)都有自己的UICollectionViewLayoutAttributes
// 每一个indexPath都有自己的UICollectionViewLayoutAttributes
}
/** 有效距离:当item的中间x距离屏幕的中间x在HMActiveDistance以内,才会开始放大, 其它情况都是缩小 */
static CGFloat const HMActiveDistance = 150;
/** 缩放因素: 值越大, item就会越大 */
static CGFloat const HMScaleFactor = 0.6;
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
// 0.计算可见的矩形框
CGRect visiableRect;
visiableRect.size = self.collectionView.frame.size;
visiableRect.origin = self.collectionView.contentOffset;
// 1.取得默认的cell的UICollectionViewLayoutAttributes
NSArray *array = [super layoutAttributesForElementsInRect:rect];
// 计算屏幕最中间的x
CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;
// 2.遍历所有的布局属性,修改之后再返回
for (UICollectionViewLayoutAttributes *attrs in array) {
// 如果不在屏幕上,直接跳过
if (!CGRectIntersectsRect(visiableRect, attrs.frame)) continue;
// 每一个item的中点x
CGFloat itemCenterX = attrs.center.x;
// 差距越小, 缩放比例越大
// 根据跟屏幕最中间的距离计算缩放比例
CGFloat scale = 1 + HMScaleFactor * (1 - (ABS(itemCenterX - centerX) / HMActiveDistance));
attrs.transform = CGAffineTransformMakeScale(scale, scale);
}
return array;
}
@end
同样省略model和view代码, 在ViewController实现如下代码:
#import "ViewController.h"
#import "HMImageCell.h"
#import "HMLineLayout.h"
@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) NSMutableArray *images;
@property (nonatomic, weak) UICollectionView *collectionView;
@end
@implementation ViewController
static NSString *const ID = @"image";
- (NSMutableArray *)images
{
if (!_images) {
self.images = [[NSMutableArray alloc] init];
for (int i = 1; i<=20; i++) {
[self.images addObject:[NSString stringWithFormat:@"%d", I]];
}
}
return _images;
}
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat w = self.view.frame.size.width;
CGRect rect = CGRectMake(0, 100, w, 200);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:[[HMLineLayout alloc] init]];
collectionView.dataSource = self;
collectionView.delegate = self;
[collectionView registerNib:[UINib nibWithNibName:@"HMImageCell" bundle:nil] forCellWithReuseIdentifier:ID];
[self.view addSubview:collectionView];
self.collectionView = collectionView;
// UICollectionViewLayout
// UICollectionViewFlowLayout
}
//点击空白会在相册浏览布局和系统默认布局之间切换
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self.collectionView.collectionViewLayout isKindOfClass:[HMLineLayout class]]) {
[self.collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];
} else {
[self.collectionView setCollectionViewLayout:[[HMLineLayout alloc] init] animated:YES];
}
}
#pragma mark - <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.images.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
HMImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
cell.image = self.images[indexPath.item];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
// 删除模型数据
[self.images removeObjectAtIndex:indexPath.item];
// 删UI(刷新UI)
[collectionView deleteItemsAtIndexPaths:@[indexPath]];
}
@end
运行代码, 就实现了如上的图片浏览效果。
3. 切换布局
效果图如下,实现点击空白在两个布局之间切换:自定义流水布局HMStackLayout和HMCircleLayout都继承于UICollectionViewLayout, 代码如下:
HMStackLayout.h文件
#import <UIKit/UIKit.h>
@interface HMStackLayout : UICollectionViewLayout
@end
HMStackLayout.m文件
#define HMRandom0_1 (arc4random_uniform(100)/100.0)
#import "HMStackLayout.h"
@implementation HMStackLayout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
//- (CGSize)collectionViewContentSize
//{
// return CGSizeMake(500, 500);
//}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *angles = @[@0, @(-0.2), @(-0.5), @(0.2), @(0.5)];
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.size = CGSizeMake(100, 100);
attrs.center = CGPointMake(self.collectionView.frame.size.width * 0.5, self.collectionView.frame.size.height * 0.5);
if (indexPath.item >= 5) {
attrs.hidden = YES;
} else {
attrs.transform = CGAffineTransformMakeRotation([angles[indexPath.item] floatValue]);
// zIndex越大,就越在上面
attrs.zIndex = [self.collectionView numberOfItemsInSection:indexPath.section] - indexPath.item;
}
return attrs;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *array = [NSMutableArray array];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i<count; i++) {
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[array addObject:attrs];
}
return array;
}
@end
HMCircleLayout.h文件
#import <UIKit/UIKit.h>
@interface HMCircleLayout : UICollectionViewLayout
@end
HMCircleLayout.m文件
#import "HMCircleLayout.h"
@implementation HMCircleLayout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.size = CGSizeMake(50, 50);
// 圆的半径
CGFloat circleRadius = 70;
CGPoint circleCenter = CGPointMake(self.collectionView.frame.size.width * 0.5, self.collectionView.frame.size.height * 0.5);
// 每个item之间的角度
CGFloat angleDelta = M_PI * 2 / [self.collectionView numberOfItemsInSection:indexPath.section];
// 计算当前item的角度
CGFloat angle = indexPath.item * angleDelta;
attrs.center = CGPointMake(circleCenter.x + circleRadius * cosf(angle), circleCenter.y - circleRadius * sinf(angle));
attrs.zIndex = indexPath.item;
return attrs;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *array = [NSMutableArray array];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i<count; i++) {
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[array addObject:attrs];
}
return array;
}
@end
下面在ViewController里面就可以直接使用了:
#import "ViewController.h"
#import "HMImageCell.h"
#import "HMStackLayout.h"
#import "HMCircleLayout.h"
@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) NSMutableArray *images;
@property (nonatomic, weak) UICollectionView *collectionView;
@end
@implementation ViewController
static NSString *const ID = @"image";
- (NSMutableArray *)images
{
if (!_images) {
self.images = [[NSMutableArray alloc] init];
for (int i = 1; i<=20; i++) {
[self.images addObject:[NSString stringWithFormat:@"%d", i]];
}
}
return _images;
}
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat w = self.view.frame.size.width;
CGRect rect = CGRectMake(0, 100, w, 200);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:[[HMCircleLayout alloc] init]];
collectionView.dataSource = self;
collectionView.delegate = self;
[collectionView registerNib:[UINib nibWithNibName:@"HMImageCell" bundle:nil] forCellWithReuseIdentifier:ID];
[self.view addSubview:collectionView];
self.collectionView = collectionView;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self.collectionView.collectionViewLayout isKindOfClass:[HMStackLayout class]]) {
[self.collectionView setCollectionViewLayout:[[HMCircleLayout alloc] init] animated:YES];
} else {
[self.collectionView setCollectionViewLayout:[[HMStackLayout alloc] init] animated:YES];
}
}
#pragma mark - <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.images.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
HMImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
cell.image = self.images[indexPath.item];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
// 删除模型数据
[self.images removeObjectAtIndex:indexPath.item];
// 删UI(刷新UI)
[collectionView deleteItemsAtIndexPaths:@[indexPath]];
}
@end
运行之后,点击空白,即可在两个布局之间切换。