上一篇简述了UICollectionView的属性及方法,本篇实际应用练习使用。
具体属性及方法可以参考上一篇UICollectionView简介:UICollectionView简介
实例1,首先看一下效果图8-1:
下面贴上代码,cell是自定义模型,不贴了,注重UICollectionView用法。
//创建布局
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
//滚动方向
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
//组间距
flowLayout.sectionInset = UIEdgeInsetsMake(10, 20, 10, 20);
@interface TestViewController ()
@property (nonatomic, strong) NSArray *array1;
@property (nonatomic, strong) NSArray *array2;
@property (nonatomic, strong) NSArray *array3;
@end
@implementation TestViewController
static NSString * const reuseIdentifier1 = @"Cell1";
static NSString * const reuseIdentifier2 = @"Cell2";
static NSString * const reuseIdentifier3 = @"Cell3";
static NSString * const Reusable = @"Reusable";
- (void)viewDidLoad {
[super viewDidLoad];
//设置背景
self.collectionView.backgroundColor = [UIColor whiteColor];
//不回弹
self.collectionView.bounces = NO;
//隐藏垂直滚动条
self.collectionView.showsVerticalScrollIndicator = NO;
//注册cell
[self.collectionView registerClass:[TVACell class] forCellWithReuseIdentifier:reuseIdentifier1];
[self.collectionView registerClass:[TVBCell class] forCellWithReuseIdentifier:reuseIdentifier2];
[self.collectionView registerClass:[TVCCell class] forCellWithReuseIdentifier:reuseIdentifier3];
//注册ReusableView
[self.collectionView registerClass:[TSView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:Reusable];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return self.array3 + 2;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (section == 0) {
return 1;
} else if (section == 1) {
return 3;
}
TVCModel *model = self.array3[section - 2];
return model.array.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
TVACell *cell = [TVACell cellWithCollectionView:collectionView cellForItemAtIndexPath:indexPath];
cell = [cell initWithArray:self.array1];
return cell;
} else if (indexPath.section == 1) {
TVBCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier2 forIndexPath:indexPath];
TVBModel *model = self.array2[indexPath.item];
cell.model = model;
return cell;
}
TVCCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier3 forIndexPath:indexPath];
TVCModel *model = self.array3[indexPath.section - 2];
cell.model = model.array[indexPath.item];
return cell;
}
//cell尺寸
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
return CGSizeMake(mainW, mainH * 0.23);
} else if (indexPath.section == 1) {
return CGSizeMake(mainW * 0.25, mainW * 0.35);
}
CGFloat W = mainW * 0.25;
return CGSizeMake(W, W);
}
//cell的最小行间距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 10.0f;
}
//margin
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
if (section == 0) {
return UIEdgeInsetsMake(0, 0, 0, 0);
}
return UIEdgeInsetsMake(10, 20, 10, 20);
}
//cell的最小列间距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return (mainW - mainW * 0.25 * 3) / 4;
}
//设置顶部的大小
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
if (section == 0) {
CGSize size = {0, 0};
return size;
}
CGSize size = {0, 40};
return size;
}
//追加视图
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
TSView *reusable = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:Reusable forIndexPath:indexPath];
reusable.delegate = self;
reusable.label.text = @"第二组追加视图";
reusable.button.hidden = NO;
return reusable;
}
} else if(indexPath.section > 1) {
TVCModel *model = self.array3[indexPath.section - 2];
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
TSView *reusable = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:Reusable forIndexPath:indexPath];
reusable.model = model;
reusable.label.text = @"第三组追加视图";
reusable.button.hidden = YES;
return reusable;
}
}
return nil;
}
//点击方法
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 1) {
} else if (indexPath.section > 1) {
}
}
@end
实例2,自定义了一个圆形布局,效果如图8-2:
下面贴上代码:
ViewController:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "HWCircleLayout.h"
#import "HWCollectionViewCell.h"
@interface ViewController ()<UICollectionViewDataSource>
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) NSArray *imageArray;
@end
static NSString * const reuseIdentifier = @"Cell";
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
self.imageArray = @[@"14", @"01", @"03", @"04", @"05", @"07", @"09", @"10", @"11", @"12", @"13", @"00"];
HWCircleLayout *layout = [[HWCircleLayout alloc] init];
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, 400) collectionViewLayout:layout];
collectionView.dataSource = self;
collectionView.backgroundColor = [UIColor whiteColor];
collectionView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"allen.jpg"]];
collectionView.backgroundView.alpha = 0.5;
[self.view addSubview:collectionView];
self.collectionView = collectionView;
[self.collectionView registerClass:[HWCollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.imageArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
HWCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.imageView.image = [UIImage imageNamed: self.imageArray[indexPath.item]];
return cell;
}
@end
HWCollectionViewCell:
#import <UIKit/UIKit.h>
@interface HWCollectionViewCell : UICollectionViewCell
@property (nonatomic, weak) UIImageView *imageView;
@end
#import "HWCollectionViewCell.h"
@implementation HWCollectionViewCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CGFloat w = [UIScreen mainScreen].bounds.size.width * 0.2;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, w, w)];
imageView.layer.cornerRadius = 10;
imageView.layer.masksToBounds = YES;
[self addSubview:imageView];
self.imageView = imageView;
}
return self;
}
@end
HWCircleLayout:
#import <UIKit/UIKit.h>
@interface HWCircleLayout : UICollectionViewLayout
@end
#import "HWCircleLayout.h"
@implementation HWCircleLayout
//返回YES,边界发生改变,自动刷新布局
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
//布局item属性
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
//创建实例
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGFloat w = [UIScreen mainScreen].bounds.size.width * 0.2;
//设置item的大小
attributes.size = CGSizeMake(w, w);
//设置圆的半径
CGFloat circleRadius = self.collectionView.frame.size.width * 0.35;
//设置圆的中心点
CGPoint circleCenter = CGPointMake(self.collectionView.frame.size.width * 0.5, self.collectionView.frame.size.height * 0.5);
//计算每一个item之间的角度
CGFloat itemAngle = M_PI * 2 / [self.collectionView numberOfItemsInSection:indexPath.section];
//计算当前item的角度
CGFloat currentAngle = indexPath.item * itemAngle;
//计算当前item的中心
CGFloat x = circleCenter.x + cos(currentAngle) * circleRadius;
CGFloat y = circleCenter.y - sin(currentAngle) * circleRadius;
//定位当前item的位置
attributes.center = CGPointMake(x, y);
//设置item的顺序,越后面的显示在前面
attributes.zIndex = indexPath.item;
return attributes;
}
//设置cell的布局属性(包括item、header、footer)
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *array = [NSMutableArray array];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
//给每一个item创建并设置布局属性
for (int i = 0; i < count; i++) {
//创建item的布局属性
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[array addObject:attrs];
}
return array;
}
@end
实例3,自定义UICollectionViewFlowLayout,实现书架效果如图8-3:
下面贴上代码:
ViewController:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "HWBooksShelfFlowLayout.h"
#import "HWBooksShelfVC.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self creatControl];
}
- (void)creatControl
{
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 100, 50)];
[btn setTitle:@"进入书架" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(btnOnClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)btnOnClick
{
HWBooksShelfFlowLayout *flowLayout = [[HWBooksShelfFlowLayout alloc] init];
HWBooksShelfVC *vc = [[HWBooksShelfVC alloc] initWithCollectionViewLayout:flowLayout];
[self presentViewController:vc animated:YES completion:nil];
}
@end
HWBooksShelfVC:
#import <UIKit/UIKit.h>
@interface HWBooksShelfVC : UICollectionViewController
@end
#import "HWBooksShelfVC.h"
#define mainW [UIScreen mainScreen].bounds.size.width
@interface HWBooksShelfVC ()
@end
@implementation HWBooksShelfVC
static NSString * const reuseIdentifier = @"Cell";
- (void)viewDidLoad {
[super viewDidLoad];
self.collectionView.showsVerticalScrollIndicator = NO;
self.collectionView.backgroundColor = [UIColor whiteColor];
// Register cell classes
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 20;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cien"]];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(mainW * 0.25, mainW * 0.308);
}
//cell的最小行间距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return mainW * 0.175;
}
//margin
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0, mainW * 0.05, 0, mainW * 0.05);
}
//cell的最小列间距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return mainW * 0.075;
}
//设置顶部的大小
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(0, mainW * 0.16);
}
@end
HWBooksShelfFlowLayout:
#import <UIKit/UIKit.h>
@interface HWBooksShelfFlowLayout : UICollectionViewFlowLayout
@end
#import "HWBooksShelfFlowLayout.h"
#import "HWBooksShelfReusableView.h"
#define mainW [UIScreen mainScreen].bounds.size.width
@implementation HWBooksShelfFlowLayout
- (void)prepareLayout
{
[super prepareLayout];
//注册Decoration View
[self registerClass:[HWBooksShelfReusableView class] forDecorationViewOfKind:@"HWBooksShelfReusableView"];
}
//Decoration View的布局
- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)decorationViewKind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:decorationViewKind withIndexPath:indexPath];
attributes.frame = CGRectMake(mainW * 0.026, mainW * 0.447 + mainW * 0.483 * indexPath.item, mainW * 0.948, mainW * 0.102);
attributes.zIndex = -1;
return attributes;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *array = [NSMutableArray array];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i < count; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[array addObject:[self layoutAttributesForDecorationViewOfKind:@"HWBooksShelfReusableView"atIndexPath:indexPath]];
}
for (int i = 0; i < count; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[array addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
return array;
}
@end
HWBooksShelfReusableView:
#import <UIKit/UIKit.h>
@interface HWBooksShelfReusableView : UICollectionReusableView
@end
#import "HWBooksShelfReusableView.h"
#define mainW [UIScreen mainScreen].bounds.size.width
@implementation HWBooksShelfReusableView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, mainW * 0.948, mainW * 0.102)];
imageView.image = [UIImage imageNamed:@"decoration"];
[self addSubview:imageView];
}
return self;
}
@end
实例4,自定义UICollectionViewFlowLayout,聚焦放大图片,如图:
下面贴上代码:
ViewController:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "HWHorizontalFlowLayout.h"
#define mainW [UIScreen mainScreen].bounds.size.width
#define mainH [UIScreen mainScreen].bounds.size.height
#define KNum 10000
@interface ViewController ()<UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) NSArray *imageArray;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, weak) UIPageControl *pageControl;
@end
@implementation ViewController
static NSString * const reuseIdentifier = @"flowLayoutTest";
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
_imageArray = @[@"kbo", @"kbt", @"kbf"];
//创建控件
[self creatControl];
//注册标识
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
//初始化位置(设置为数据中间位置)
[self.collectionView setContentOffset:CGPointMake(mainW * 0.65 * (_imageArray.count * KNum * 0.5 + 1), self.collectionView.contentOffset.y) animated:YES];
}
- (void)creatControl
{
//collectionView
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, mainW, mainH) collectionViewLayout:[[HWHorizontalFlowLayout alloc] init]];
_collectionView.backgroundColor = [UIColor clearColor];
_collectionView.showsVerticalScrollIndicator = NO;
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.delegate = self;
_collectionView.dataSource = self;
[self.view addSubview:_collectionView];
//pageControl
UIPageControl *pageControl = [[UIPageControl alloc]initWithFrame:CGRectMake((mainW - 80) * 0.5, mainH - 100, 80, 30)];
pageControl.numberOfPages = _imageArray.count;
pageControl.currentPage = 1;
pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
pageControl.userInteractionEnabled = NO;
[self.view addSubview:pageControl];
_pageControl = pageControl;
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
//返回一个大数据,保证无限滚动
return _imageArray.count * KNum;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:_imageArray[indexPath.item % _imageArray.count]]];
return cell;
}
//点击事件
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"点击了图片%ld", indexPath.item % _imageArray.count);
//do something...
}
//滑动事件
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//更新pageControl
_pageControl.currentPage = (int)(scrollView.contentOffset.x / (mainW * 0.65)) % _imageArray.count;
}
@end
HWHorizontalFlowLayout:
#import <UIKit/UIKit.h>
@interface HWHorizontalFlowLayout : UICollectionViewFlowLayout
@end
#import "HWHorizontalFlowLayout.h"
#define mainW [UIScreen mainScreen].bounds.size.width
@implementation HWHorizontalFlowLayout
- (instancetype)init
{
if (self = [super init]) {
self.minimumLineSpacing = 0;
self.minimumInteritemSpacing = 0;
self.itemSize = CGSizeMake(mainW * 0.65, mainW * 0.963);
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
}
return self;
}
- (void)prepareLayout
{
[super prepareLayout];
CGFloat inset = (self.collectionView.frame.size.width - self.itemSize.width) * 0.5;
self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
}
//边界发生改变,是否刷新布局,返回YES时,重新刷新布局调用layoutAttributesForElementsInRect方法
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
//设置cell的布局属性,一个cell对应一个UICollectionViewLayoutAttributes对象
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *array = [super layoutAttributesForElementsInRect:rect];
//collectionView中心点的值
CGFloat centerX = self.collectionView.frame.size.width * 0.5 + self.collectionView.contentOffset.x;
//遍历更改
for (UICollectionViewLayoutAttributes *atts in array) {
//cell的中心点x和collectionView最中心点的x值的间距
CGFloat space = ABS(atts.center.x - centerX);
CGFloat scale = 1 - space/self.collectionView.frame.size.width * 0.2;
atts.transform = CGAffineTransformMakeScale(scale, scale);
}
return array;
}
//这个方法的返回值,就决定了collectionView停止滚动时的偏移量
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
//计算出最终显示的矩形框
CGRect rect;
//最终要停下来的X
rect.origin.x = proposedContentOffset.x;
rect.origin.y = 0;
rect.size = self.collectionView.frame.size;
//获得计算好的属性
NSArray *array = [super layoutAttributesForElementsInRect:rect];
//计算collection中心点X
CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
CGFloat minSpace = MAXFLOAT;
for (UICollectionViewLayoutAttributes *attrs in array) {
if (ABS(minSpace) > ABS(attrs.center.x - centerX)) {
minSpace = attrs.center.x - centerX;
}
}
//修改原有的偏移量
proposedContentOffset.x += minSpace;
return proposedContentOffset;
}
@end