UICollectionView基础
- UICollectionViewFlowLayout:视图布局对象(流水布局:一行排满,自动排到下行),继承自UICollectionViewLayout。UICollectionViewLayout内有一个collectionView属性,所有的视图布局对象都继承自UICollectionViewLayout。
- 若我们要自定义布局对象,我们一般继承UICollectionViewFlowLayout,然后重写里面的一些方法就可以了。
- 需要实现三个协议;UICollectionViewDataSource(数据源)、UICollectionViewDelegateFlowLayout(视图布局),自定义布局需要实现UICollectionViewDataSource、UICollectionViewDelegate两个协议即可。
一、自定义线性布局
- 首先要继承与流水布局UICollectionViewFlowLayout
#import <UIKit/UIKit.h>
@interface LineCollectionViewLayout : UICollectionViewFlowLayout
@end
#import "LineCollectionViewLayout.h"
@implementation LineCollectionViewLayout
- (instancetype)init{
if (self = [super init]) {
}
return self;
}
- (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);
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;
for (UICollectionViewLayoutAttributes *attrs in array) {
CGFloat delta = ABS(attrs.center.x - centerX);
CGFloat scale = 1 - delta / self.collectionView.frame.size.width;
attrs.transform = CGAffineTransformMakeScale(scale, scale);
}
return array;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{
CGRect rect;
rect.origin.y = 0;
rect.origin.x = proposedContentOffset.x;
rect.size = self.collectionView.frame.size;
NSArray *array = [super layoutAttributesForElementsInRect:rect];
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
自定义环形布局
- 同样要继承与流水布局UICollectionViewFlowLayout
#import <UIKit/UIKit.h>
@interface CircleCollectionViewLayout : UICollectionViewFlowLayout
@end
#import "CircleCollectionViewLayout.h"
@interface CircleCollectionViewLayout()
@property (nonatomic, strong) NSMutableArray *attrsArray;
@end
@implementation CircleCollectionViewLayout
- (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
对自定义布局的使用
CircleCollectionViewLayout *layout = [[CircleCollectionViewLayout alloc] init];
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([PhotoCell class]) bundle:nil] forCellWithReuseIdentifier:photoId];
- 增加 touchesBegan:方法,通过点击让两种布局相互转换
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self.collectionView.collectionViewLayout isKindOfClass:[LineCollectionViewLayout class]]) {
[self.collectionView setCollectionViewLayout:[[CircleCollectionViewLayout alloc] init] animated:YES];
} else {
LineCollectionViewLayout *layout = [[LineCollectionViewLayout alloc] init];
layout.itemSize = CGSizeMake(100, 100);
[self.collectionView setCollectionViewLayout:layout animated:YES];
}
}