自定义布局和自定义流水布局(CollectionViewLayout和CollectionViewFlowLayout)
一
- 在UIScrollView的基础上进行循环利用
+ 那怎么去做循环利用呢?
- 第一种方案:
+ 实时监控ScrollView的滚动,一旦有一个家伙离开屏幕,我们就把它放进一个数组或者是集合里面去,到时候我要用,我就把它拿过去用
+ 但是这个是很麻烦的,因为你总是得判断它有没有离开屏幕
- 第二种方案:
+ 用苹果自带的几个类:TableView或者是CollectionView
+ 因为它们本来就具备循环利用的功能
+ 但是TableView一看就不符合要求,因为它默认就是上下竖直滚动,不是左右水平滚动
+ 当然我们也可以用非主流的方式,让TableView实现水平滚动
+ 让TableView的Transform来个90°,让它里面所有的cell也翻个90°,都转过来。但这种做法有点奇葩,开发中还是不要这么搞
+ 所以我们可以用CollectionView
+ CollectionView在我们的印象中是展示像那种九宫格的样子,而且也是上下竖直滚动
+ 但是CollectionView和TableView的区别就是:
+ CollectionView它默认就支持水平滚动,你只要修改它一个属性为水平方向就行了。而TableView默认支持竖直滚动,没有属性去支持它水平滚动,除非你去搞一些非主流的做法
二 - CollectionView一定要传一个不空的Layout那个参数,因为默认的布局是九宫格,它按这种方式排的原因是它有一个流水布局。正因为给它传了一个流水布局,所以它就一行满了,就流向下一行,流水一样流下去流过来
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:[UICollectionViewlayout alloc] init]];
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 50 ; }
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { // 先要注册 UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CYCellId forIndexPath:indexPath]; cell.backgroundColor = [UIColor orangeColor]return cell;
}
// 水平滚动 self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.itemSize = CGSizeMake(100, 100);
三
*四 *
#import@interface CYLineLayout : UICollectionViewFlowLayout
@end
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { // 获得super已经计算好的布局属性(在super已经算好的基础上,再去做一些改进) NSArray *array = [super layoutAttributesForElementsInRect:rect];// 计算collectionView最中心点的x值 CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5; // 在原有布局属性的基础上进行微调 for (UICollectionViewLayoutAttributes *attrs in array) { // cell的中心点x和collectionView最中心点的x值 的间距 CGFloat delta = ABS(attrs.center.x - centerX); // 根据间距值计算cell的缩放比例 CGFloat scale = 1 - delta / self.collectionView.frame.size.width; // 设置缩放比例 attrs.transform = CGAffineTransformMakeScale(scale, scale); } return array;
}
- 计算collectionView中心点的x值
+ 要记住collectionView的坐标原点是以内容contentSize的原点为原点
+ 计算collectionView中心点的x值,千万不要用collectionView的宽度除以2。而是用collectionView的偏移量加上collectionView宽度的一半
+ 坐标原点弄错了就没有可比性了,因为后面要判断cell的中心点与collectionView中心点的差值
CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;
CGFloat delta = ABS(attrs.center.x - centerX);
ABS(A) // 表示取绝对值
CGFloat scale = 1 - delta / self.collectionView.frame.size.width; // 用1-(),是因为间距值delta和缩放比例scale是成反比的
attrs.transform = CGAffineTransformMakeScale(scale, scale);
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { return YES;}
五 - 还要实现一个方法:targetContentOffsetForProposedContentOffset:()方法。它的返回值,就决定了collectionView停止滚动时的偏移量 - 这个方法在你手离开屏幕之前会调用,也就是cell即将停止滚动的时候 (记住这一点)
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { // 计算出最终显示的矩形框 CGRect rect; rect.origin.y = 0; rect.origin.x = proposedContentOffset.x; rect.size = self.collectionView.frame.size;// 获得super已经计算好的布局属性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; // 计算collectionView最中心点的x值 CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5; // 存放最小的间距值 CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) { if (ABS(minDelta) > ABS(attrs.center.x - centerX)) { minDelta = attrs.center.x - centerX; } } // 修改原有的偏移量 proposedContentOffset.x += minDelta; return proposedContentOffset;
}
NSArray *array = [super layoutAttributesForElementsInRect:rect];
这里为什么不用self
计算collectionView最中心点的x值
objc CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
objc CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;来算呢?
同上面可知,我们最后拿到的矩形框也是不能乱传的,也是要拿到最终的哪一个矩形框(不明白,就想像一下,你往左边或者右边用手指一甩的时候,手离开的时候是一个值,最终停下来是一个值,而现在我们需要的是最终的值)
// 计算出最终显示的矩形框 CGRect rect; rect.origin.y = 0; rect.origin.x = proposedContentOffset.x; rect.size = self.collectionView.frame.size;
// 存放最小的间距值 CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) { if (ABS(minDelta) > ABS(attrs.center.x - centerX)) { minDelta = attrs.center.x - centerX; } } // 修改原有的偏移量 proposedContentOffset.x += minDelta; return proposedContentOffset;
六 - 有一个小缺陷,你会发现,一打开程序,你往左或往右滑到最左或者最右的时候,cell总是默认粘着边上,这个不太和谐,我们需要它距离左右两边都有一个距离,那我们该怎么做呢? + 这就是让我们把所有的cell,让它们往右边或者左边挪一段距离,所以就增加内边距就可以了。怎么添加内边距呢? + collectionView是继承ScrollView的,所以设置它的ContentInset就可以了 + 还一种方法通过这个布局它本来就有一个属性sectionInset ,这本来就是来控制内边距的,控制整个布局的。而且这个属性只需要设置一次 - 这里有一个给collectionView专门用来布局的方法---prepareLayout,这里一般是做初始化操作
/** * 用来做布局的初始化操作(不建议在init方法中进行布局的初始化操作--可能布局还未加到View中去,就会返回为空) */ - (void)prepareLayout { [super prepareLayout];// 设置内边距 CGFloat inset = (self.collectionView.frame.size.width - self.itemSize.width) * 0.5; self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
}
七 - 总的来说我们若要继承自这个流水布局来实现这个功能的话,肯定是要重写一些方法,告诉它一些内部的行为,它才知道怎么去显示那个东西,我们用了一下的方法: + 我们首先得实现prepareLayout方法,做一些初始化 + 然后,我们实现layoutAttributesForElementsInRect:方法。目的是拿出它计算好的布局属性来做一个微调,这样可以导致我们的cell可以变大或者变小 + 然后实现targetContentOffsetForProposedContentOffset:方法。它的目的是告诉当我手松开,cell停止滚动的时候,他应该去哪儿,所以这个方法就决定了collectionView停止滚动时的偏移量 + 最后shouldInvalidateLayoutForBoundsChange:这个方法的价值就是告诉它你只要稍微往左或者往右挪一下,你就重新刷新,只要你重新刷新,它就会重新根据你cell的中心点的X值距离你collectionView中心点的X值来决定你的缩放比例。这样就保证了我们每动一点点,比例都在变,所以我们要动一下刷新一下。也就是当collectionView的显示范围发生改变的时候,是否需要重新刷新布局,一旦重新刷新布局,就会重新调用下面的方法:1.prepareLayout2.layoutAttributesForElementsInRect:方法 - 关于做这个效果有一个挺牛逼的三方框架:iCarousel大家可以参考一下
八 - 在CYLineLayout.h文件中
#import@interface CYLineLayout : UICollectionViewFlowLayout
@end
#import "CYLineLayout.h"@implementation CYLineLayout
/**
1.prepareLayout 2.layoutAttributesForElementsInRect:方法 */
/**
(void)prepareLayout { [super prepareLayout];
// 水平滚动 self.scrollDirection = UICollectionViewScrollDirectionHorizontal; // 设置内边距 CGFloat inset = (self.collectionView.frame.size.width - self.itemSize.width) * 0.5; self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset); }
/** UICollectionViewLayoutAttributes attrs; 1.一个cell对应一个UICollectionViewLayoutAttributes对象 2.UICollectionViewLayoutAttributes对象决定了cell的frame / /
(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { // 获得super已经计算好的布局属性 NSArray *array = [super layoutAttributesForElementsInRect:rect] ;
// 计算collectionView最中心点的x值 CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;
// 在原有布局属性的基础上,进行微调 for (UICollectionViewLayoutAttributes *attrs in array) {
// cell的中心点x 和 collectionView最中心点的x值 的间距
CGFloat delta = ABS(attrs.center.x - centerX);
// 根据间距值 计算 cell的缩放比例
CGFloat scale = 1 - delta / self.collectionView.frame.size.width;
// 设置缩放比例
attrs.transform = CGAffineTransformMakeScale(scale, scale);
}
return array;
}
/**
这个方法的返回值,就决定了collectionView停止滚动时的偏移量
/
(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { // 计算出最终显示的矩形框 CGRect rect; rect.origin.y = 0; rect.origin.x = proposedContentOffset.x; rect.size = self.collectionView.frame.size;
// 获得super已经计算好的布局属性 NSArray *array = [super layoutAttributesForElementsInRect:rect];
// 计算collectionView最中心点的x值 CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
// 存放最小的间距值 CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) {
if (ABS(minDelta) > ABS(attrs.center.x - centerX)) {
minDelta = attrs.center.x - centerX;
}
}
// 修改原有的偏移量 proposedContentOffset.x += minDelta; return proposedContentOffset; }
@end
九 - 假如我们要监听cell的点击,要怎么办呢?上面这讲的这些都和CollectionViewCell的点击没有关系,只是和布局有关。监听CollectionViewCell的点击和CollectionViewCell的布局没有任何关系,布局只负责展示,格子里面是什么内容,还是取决于cell - 布局的作用仅仅是控制cell的排布 + 控制器先成为CollectionViewCell的代理:UICollectionViewDelegate - 现在要把数据填充上去,让它显示相册了,所以自定义CollectionViewCell--CYPhotoCell,由于里面是固定死的,所以加一个Xib文件,里面加一个ImageView,拖线给一个属性,给ImageView一个标识photo - 给cell里面的相片加上一个相册相框的效果--两种方案: + 第一种方案:在Xib的ImageView的布局上下左右都给一个10的间距,给一个white的背景颜色 + 第二种方案:给我们的ImageView加一个图层就可以了
- (void)awakeFromNib { self.imageView.layer.borderColor = [UIColor whiteColor].CGColor; self.imageView.layer.borderWidth = 10; }
#import@interface CYPhotoCell : UICollectionViewCell /** 图片名 */ @property (nonatomic, copy) NSString *imageName; @end
#import "CYPhotoCell.h"@interface CYPhotoCell()
@property (weak, nonatomic) IBOutlet UIImageView *imageView; @end
@implementation CYPhotoCell
(void)awakeFromNib { self.imageView.layer.borderColor = [UIColor whiteColor].CGColor; self.imageView.layer.borderWidth = 10; }
(void)setImageName:(NSString *)imageName { _imageName = [imageName copy];
self.imageView.image = [UIImage imageNamed:imageName]; }
@end
#import "ViewController.h" #import "CYLineLayout.h" #import "CYPhotoCell.h"@interface ViewController () @end
@implementation ViewController
static NSString * const CYPhotoId = @"photo";
(void)viewDidLoad { [super viewDidLoad];
// 创建布局 CYLineLayout *layout = [[CYLineLayout alloc] init]; layout.itemSize = CGSizeMake(100, 100);
// 创建CollectionView CGFloat collectionW = self.view.frame.size.width; CGFloat collectionH = 200; CGRect frame = CGRectMake(0, 150, collectionW, collectionH); UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout]; collectionView.dataSource = self; collectionView.delegate = self; [self.view addSubview:collectionView];
// 注册 [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CYPhotoCell class]) bundle:nil] forCellWithReuseIdentifier:CYPhotoId]; }
#pragma mark -
(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 20; }
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { CYPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CYPhotoId forIndexPath:indexPath];
cell.imageName = [NSString stringWithFormat:@"%zd", indexPath.item + 1];
return cell; }
#pragma mark -
十 ####自定义流水布局
重写prepareLayout方法
重写layoutAttributesForElementsInRect:方法
重写shouldInvalidateLayoutForBoundsChange:方法
重写targetContentOffsetForProposedContentOffset:方法
自定义布局--CollectionViewLayout--格子布局
// 创建UICollectionViewLayoutAttributes NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0]; UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
#import "ViewController.h" #import "CYGridLayout.h" #import "CYPhotoCell.h"@interface ViewController () @end
@implementation ViewController
static NSString * const CYPhotoId = @"photo";
(void)viewDidLoad { [super viewDidLoad];
// 创建布局 CYGridLayout *layout = [[CYGridLayout alloc] init];
// 创建CollectionView UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; collectionView.dataSource = self; collectionView.delegate = self; [self.view addSubview:collectionView];
// 注册 [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CYPhotoCell class]) bundle:nil] forCellWithReuseIdentifier:CYPhotoId]; }
#import "CYGridLayout.h"@interface CYGridLayout() /** 所有的布局属性 */ @property (nonatomic, strong) NSMutableArray *attrsArray; @end
@implementation CYGridLayout
(NSMutableArray *)attrsArray { if (!_attrsArray) {
_attrsArray = [NSMutableArray array];
} return _attrsArray; }
(void)prepareLayout { [super prepareLayout];
[self.attrsArray removeAllObjects];
NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i < count; i++) {
// 创建UICollectionViewLayoutAttributes
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
// 设置布局属性
CGFloat width = self.collectionView.frame.size.width * 0.5;
if (i == 0) {
CGFloat height = width;
CGFloat x = 0;
CGFloat y = 0;
attrs.frame = CGRectMake(x, y, width, height);
} else if (i == 1) {
CGFloat height = width * 0.5;
CGFloat x = width;
CGFloat y = 0;
attrs.frame = CGRectMake(x, y, width, height);
} else if (i == 2) {
CGFloat height = width * 0.5;
CGFloat x = width;
CGFloat y = height;
attrs.frame = CGRectMake(x, y, width, height);
} else if (i == 3) {
CGFloat height = width * 0.5;
CGFloat x = 0;
CGFloat y = width;
attrs.frame = CGRectMake(x, y, width, height);
} else if (i == 4) {
CGFloat height = width * 0.5;
CGFloat x = 0;
CGFloat y = width + height;
attrs.frame = CGRectMake(x, y, width, height);
} else if (i == 5) {
CGFloat height = width;
CGFloat x = width;
CGFloat y = width;
attrs.frame = CGRectMake(x, y, width, height);
} else {
UICollectionViewLayoutAttributes *lastAttrs = self.attrsArray[i - 6];
CGRect lastFrame = lastAttrs.frame;
lastFrame.origin.y += 2 * width;
attrs.frame = lastFrame;
}
// 添加UICollectionViewLayoutAttributes
[self.attrsArray addObject:attrs];
} }
/** * 返回collectionView的内容大小 */ - (CGSize)collectionViewContentSize { int count = (int)[self.collectionView numberOfItemsInSection:0]; int rows = (count + 3 - 1) / 3; CGFloat rowH = self.collectionView.frame.size.width * 0.5; return CGSizeMake(0, rows * rowH); }
计算不是重点,你是可以总结出计算的规律的。重点是:继承自CollectionViewLayout你需要注意什么?
这里给出一个思想:
这样就实现了:
自定义布局--CollectionViewLayout--布局之间的切换
- 要求:
+ 实现一个环形布局和水平布局的相册,点击屏幕能够进行不同布局之间的切换
+ 点击cell的时候可以删除cell
- 首先通过分析,在上面第一个案例的基础上,再添加一个环形布局--CYCircleLayout,肯定也是只能继承自CollectionViewLayout
- 在这里CYCircleLayout里面就只需要实现prepareLayout方法和layoutAttributesForElementsInRect方法,不需再要重写实现collectionViewContentSize的方法,因为它不需要滚动,所以CollectionViewLayout里面所有方法的实现是看你的需求的
#import "CYCircleLayout.h"@interface CYCircleLayout() /** 布局属性 */ @property (nonatomic, strong) NSMutableArray *attrsArray; @end
@implementation CYCircleLayout
(NSMutableArray *)attrsArray { if (!_attrsArray) {
_attrsArray = [NSMutableArray array];
} return _attrsArray; }
(void)prepareLayout { [super prepareLayout];
[self.attrsArray removeAllObjects];
NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i < count; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArray addObject:attrs];
} }
(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return self.attrsArray; }
/** * 这个方法需要返回indexPath位置对应cell的布局属性 */ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { NSInteger count = [self.collectionView numberOfItemsInSection:0]; CGFloat radius = 70; // 圆心的位置 CGFloat oX = self.collectionView.frame.size.width * 0.5; CGFloat oY = self.collectionView.frame.size.height * 0.5;UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attrs.size = CGSizeMake(50, 50); if (count == 1) { attrs.center = CGPointMake(oX, oY); } else { CGFloat angle = (2 * M_PI / count) * indexPath.item; CGFloat centerX = oX + radius * sin(angle); CGFloat centerY = oY + radius * cos(angle); attrs.center = CGPointMake(centerX, centerY); } return attrs;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if ([self.collectionView.collectionViewLayout isKindOfClass:[CYLineLayout class]]) { [self.collectionView setCollectionViewLayout:[[CYCircleLayout alloc] init] animated:YES]; } else { CYLineLayout *layout = [[CYLineLayout alloc] init]; layout.itemSize = CGSizeMake(100, 100); [self.collectionView setCollectionViewLayout:layout animated:YES]; } }
@interface ViewController () /** collectionView */ @property (nonatomic, weak) UICollectionView *collectionView; /** 数据 */ @property (nonatomic, strong) NSMutableArray *imageNames; @end@implementation ViewController
static NSString * const CYPhotoId = @"photo";
_imageNames = [NSMutableArray array];
for (int i = 0; i<20; i++) {
[_imageNames addObject:[NSString stringWithFormat:@"%zd", i + 1]];
}
}
return _imageNames;
}#pragma mark - - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.imageNames.count; }
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { CYPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CYPhotoId forIndexPath:indexPath];
cell.imageName = self.imageNames[indexPath.item];
return cell; }
#pragma mark -
(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [self.imageNames removeObjectAtIndex:indexPath.item]; [self.collectionView deleteItemsAtIndexPaths:@[indexPath]]; }
if (count == 1) { attrs.center = CGPointMake(oX, oY); } else { CGFloat angle = (2 * M_PI / count) * indexPath.item; CGFloat centerX = oX + radius * sin(angle); CGFloat centerY = oY + radius * cos(angle); attrs.center = CGPointMake(centerX, centerY); }
#import "CYCircleLayout.h"@interface CYCircleLayout() /** 布局属性 */ @property (nonatomic, strong) NSMutableArray *attrsArray; @end
@implementation CYCircleLayout
(NSMutableArray *)attrsArray { if (!_attrsArray) {
_attrsArray = [NSMutableArray array];
} return _attrsArray; }
(void)prepareLayout { [super prepareLayout];
[self.attrsArray removeAllObjects];
NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i < count; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArray addObject:attrs];
} }
(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return self.attrsArray; }
/**
(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { NSInteger count = [self.collectionView numberOfItemsInSection:0]; CGFloat radius = 70; // 圆心的位置 CGFloat oX = self.collectionView.frame.size.width * 0.5; CGFloat oY = self.collectionView.frame.size.height * 0.5;
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.size = CGSizeMake(50, 50); if (count == 1) {
attrs.center = CGPointMake(oX, oY);
} else {
CGFloat angle = (2 * M_PI / count) * indexPath.item;
CGFloat centerX = oX + radius * sin(angle);
CGFloat centerY = oY + radius * cos(angle);
attrs.center = CGPointMake(centerX, centerY);
}
return attrs; } @end
#import "ViewController.h" #import "CYLineLayout.h" #import "CYCircleLayout.h" #import "CYPhotoCell.h"@interface ViewController () /** collectionView / @property (nonatomic, weak) UICollectionView collectionView; / 数据 */ @property (nonatomic, strong) NSMutableArray *imageNames; @end
@implementation ViewController
static NSString * const CYPhotoId = @"photo";
(NSMutableArray *)imageNames { if (!_imageNames) {
_imageNames = [NSMutableArray array];
for (int i = 0; i<20; i++) {
[_imageNames addObject:[NSString stringWithFormat:@"%zd", i + 1]];
}
} return _imageNames; }
(void)viewDidLoad { [super viewDidLoad];
// 创建布局 CYCircleLayout *layout = [[CYCircleLayout alloc] init];
// 创建CollectionView CGFloat collectionW = self.view.frame.size.width; CGFloat collectionH = 200; CGRect frame = CGRectMake(0, 150, collectionW, collectionH); UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout]; collectionView.dataSource = self; collectionView.delegate = self; [self.view addSubview:collectionView]; self.collectionView = collectionView;
// 注册 [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CYPhotoCell class]) bundle:nil] forCellWithReuseIdentifier:CYPhotoId];
// 继承UICollectionViewLayout // 继承UICollectionViewFlowLayout }
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if ([self.collectionView.collectionViewLayout isKindOfClass:[XMGLineLayout class]]) {
[self.collectionView setCollectionViewLayout:[[XMGCircleLayout alloc] init] animated:YES];
} else {
XMGLineLayout *layout = [[XMGLineLayout alloc] init];
layout.itemSize = CGSizeMake(100, 100);
[self.collectionView setCollectionViewLayout:layout animated:YES];
} }
#pragma mark -
(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.imageNames.count; }
(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { CYPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CYPhotoId forIndexPath:indexPath];
cell.imageName = self.imageNames[indexPath.item];
return cell; }
#pragma mark -