之前使用UICollectionView只把它当成UITableView的加强版来使用,并不特别理解原来UICollectionViewLayout有着挺强大的功能,在这里模仿一下网上的源码,写一份让自己印象更加深刻。
UICollectionViewLayout 实现 CircleLayout
在这里,我使用的是XIB实现UICollectionView。
这里是ViewController里面的viewDidLoad()
// Add Gesture
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[self.circleCV addGestureRecognizer:tapGesture];
// 设置 UICollectionViewLayout
self.circleCV.collectionViewLayout = [[CircleLayout alloc] init];
// Register UICollectionViewCell
UINib *circleNib = [UINib nibWithNibName:@"CircleCollectionViewCell" bundle:[NSBundle mainBundle]];
[self.circleCV registerNib:circleNib forCellWithReuseIdentifier:@"CELL"];
[self.circleCV registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:@"FirstSupplementary" withReuseIdentifier:@"ReuseID"];
[self.circleCV registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:@"SecondSupplementary" withReuseIdentifier:@"ReuseID"];
在这里只用实现 UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return self.cellCount;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
CircleCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath];
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"ReuseID" forIndexPath:indexPath];
view.backgroundColor = [UIColor greenColor];
UILabel *label = [[UILabel alloc] init];
label.text = kind;
label.font = [UIFont systemFontOfSize:24];
[label sizeToFit];
label.center = CGPointMake(view.bounds.size.width/2, view.bounds.size.height/2);
[view addSubview:label];
return view;
}
UICollectionViewCell只是一个50X50的UIImageView,在这里我就不贴上来了。
UICollectionView有三个部分构成
- Cells
- Supplementary Views 追加视图 (类似Header或者Footer)
- Decoration Views 装饰视图 (用作背景展示)
下一步我们需要建立一个继承于UICollectionViewLayout的子类
每一个layout都需要实现以下方法:
- collectionViewContentSize
- shouldInvalidateLayoutForBoundsChange:
- layoutAttributesForElementsInRect:
- layoutAttributesForItemAtIndexPath:
- layoutAttributesForSupplementaryViewOfKind:atIndexPath: (如果layout 支持 supplementary views)
- layoutAttributesForDecorationViewWithReuseIdentifier:atIndexPath: (如果layout 支持 decoration views)
当UICollectionView发生数据改变的时候,比如插入和删除,需要实现以下方法:
- initialLayoutAttributesForInsertedItemAtIndexPath:
- initialLayoutAttributesForInsertedSupplementaryElementOfKind:atIndexPath:
- finalLayoutAttributesForDeletedItemAtIndexPath:
- finalLayoutAttributesForDeletedSupplementaryElementOfKind:atIndexPath:
实现代码:
- (void)prepareLayout{
[super prepareLayout];
[self registerClass:[CollectionReusableView class] forDecorationViewOfKind:@"MyDecoration"];
self.size = self.collectionView.frame.size;
self.cellCount = [[self collectionView] numberOfItemsInSection:0];
self.center = CGPointMake(self.size.width / 2.0, self.size.height / 2.0);
self.radius = MIN(self.size.width, self.size.height) / 2.5;
}
- (CGSize)collectionViewContentSize{
return [self collectionView].frame.size;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.size = CGSizeMake(50, 50);
attributes.center = CGPointMake(self.center.x + self.radius * cosf(2*indexPath.item*M_PI/self.cellCount), self.center.y + self.radius * sinf(2*indexPath.item*M_PI/self.cellCount));
return attributes;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];
attributes.size = CGSizeMake(260, 40);
if([elementKind isEqual:@"FirstSupplementary"]){
attributes.center = CGPointMake(self.size.width/2, 40);
}
else{
attributes.center = CGPointMake(self.size.width/2, self.size.height-40);
}
return attributes;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:elementKind withIndexPath:indexPath];
attributes.size = CGSizeMake(140, 40);
attributes.center = CGPointMake(self.size.width/2, self.size.height/2);
return attributes;
}
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray* array = [NSMutableArray array];
for (NSInteger i=0 ; i < self.cellCount; i++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[array addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
//add first supplementaryView
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:@"FirstSupplementary" atIndexPath:indexPath];
[array addObject:attributes];
//add second supplementaryView
attributes = [self layoutAttributesForSupplementaryViewOfKind:@"SecondSupplementary" atIndexPath:indexPath];
[array addObject:attributes];
//add decorationView
attributes = [self layoutAttributesForDecorationViewOfKind:@"MyDecoration" atIndexPath:indexPath];
[array addObject:attributes];
return array;
}
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedItemAtIndexPath:(NSIndexPath *)itemIndexPath{
UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
attributes.alpha = 0.0;
attributes.center = CGPointMake(self.center.x, self.center.y);
return attributes;
}
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedItemAtIndexPath:(NSIndexPath *)itemIndexPath{
UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
attributes.alpha = 0.0;
attributes.center = CGPointMake(self.center.x, self.center.y);
attributes.transform3D = CATransform3DMakeScale(0.1, 0.1, 1.0);
return attributes;
}
最后放上实现效果图:
![](https://img.haomeiwen.com/i1323646/ce20ac5dcc19da2e.png)
网友评论