上一篇簡述了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