UICollectionView的布局是可以自己定义的,在这篇博客中先在上篇博客的基础上进行扩充,我们先使用UICollectionViewFlowLayout,然后好好的介绍一下UICollectionView的一些回调方法,主要包括UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,UICollectionViewDelegate相关回调方法,并通过实例来介绍每个回调的用法。并且给每个Section添加定制的Header和Footer,好废话少说进入今天的正题。

一、Demo总览

下图是本篇博客中Demo的最终运行效果,下面是我们要做的事情:

  •     1. 给每个Section添加自定义的重用Header和Footer

  •     2.调整第一个Section的上左下右的边距(UIEdgeInsets)

  •     3.给UICollectioinView设置多选

  •     4.处理Cell的高亮事件

  •     5.处理Cell的选中事件

  •     6.调整Cell的上下左右边距

  •     7.对Cell进行编辑

                   

二、UICollectionViewDataSource介绍

1、在UICollectionViewDataSource回调方法中有一个返回Section数量的方法,如下所示,该方法和UITableView中的用法一致。在这儿我们返回5个Section,如下所示:

 #pragma mark <UICollectionViewDataSource>

 /**
* 返回Section的个数
*/
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
return ;
}

2、在UICollectionViewDataSource的回调方法中,还有一个是返回每个Section中Cell的数量的方法,在这我们返回30个Cell, 如下代码所示:

 /**
* 返回每个Section中Cell的个数
*/
- (NSInteger)collectionView: (UICollectionView *)collectionView
numberOfItemsInSection: (NSInteger)section { return ;
}

3、在UICollectionViewDataSource还有一个必须实现的方法, 就是选择我们CollectionView中所使用的Cell, 在这里我们所使用的Cell是在Storyboard上实现的,所以不需要在我们的代码中注册Cell, 之间使用重用标示符就可以获取Cell的对象,如下所示:

 /**
* 返回Cell种类
*/
- (UICollectionViewCell *)collectionView: (UICollectionView *)collectionView
cellForItemAtIndexPath: (NSIndexPath *)indexPath { //通过Cell重用标示符来获取Cell
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: reuseIdentifier
forIndexPath: indexPath]; return cell;
}

4、在UICollectionViewDataSource方法中有一个可选的方法就是为我们的Section添加Supplementary View(追加视图),下面是添Supplementary View(追加视图)的步骤。在UICollectionView中的Section中我们可以为其增加Header View和Footer View, 也就是官方文档上提到的Supplementary View(追加视图)。追加视图是可以重用的,也就是UICollectionReusableView。我们可以创建两个UICollectionReusableView的子类,一个是Header View, 另一个是Footer View。

(1)创建UICollectionReusableView

追加视图可以在Storyboard上添加,然后设置重用标示符,在代码中使用即可。这里我们是从xib文件来加载的Supplementary View, 先创建两个UICollectionReusableView子类,在创建该子类的同时创建相应的xib文件,如下所示:

    

创建Header View和Footer View的UICollectionReusableView,创建后的文件目录如下:

(2) 因为我们是从xib文件中加载的UICollectionReusableView,所以需要在相应的UICollectionView上进行注册。如果你是使用的Storyboard, 只需要在Storyboard中指定重用标示符即可。下面的代码就是在ViewDidLoad中调用注册UICollectionReusableView的方法。

 /**
* 注册Header和FooterView
* 便于在UICollectionViewDataSource中使用
*/
- (void) registerHeaderAndFooterView {
//注册headerView
//获取含有UICollectionReusableView的Nib文件。
UINib *headerNib = [UINib nibWithNibName: @"CollectionHeaderReusableView"
bundle: [NSBundle mainBundle]]; //注册重用View
[self.collectionView registerNib: headerNib
forSupplementaryViewOfKind: UICollectionElementKindSectionHeader
withReuseIdentifier: @"CollectionHeaderReusableView"]; //注册FooterView
UINib *footerNib = [UINib nibWithNibName: @"CollectionFooterReusableView"
bundle:[ NSBundle mainBundle]]; [self.collectionView registerNib: footerNib
forSupplementaryViewOfKind: UICollectionElementKindSectionFooter
withReuseIdentifier: @"CollectionFooterReusableView"]; }

(3)在UICollectionViewDataSource中的设置Supplementary View的方法中通过Header View和Footer View的重用标示符来为我们的Section设置Supplementary View,具体代码如下所示:

 /**
* 设置Setion的Header和Footer(Supplementary View)
*/
- (UICollectionReusableView *)collectionView: (UICollectionView *)collectionView
viewForSupplementaryElementOfKind: (NSString *)kind
atIndexPath: (NSIndexPath *)indexPath{ //设置SectionHeader
if ([kind isEqualToString: UICollectionElementKindSectionHeader]) { UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderReusableView" forIndexPath:indexPath]; return view;
} //设置SectionFooter
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionFooterReusableView" forIndexPath:indexPath];
return view; }

  UICollectionViewDataSource中的四个方法在上面都进行了实现,UICollectionViewDataSource主要是负责加载数据源的,包括Section的个数,每个Section中Cell的个数,每个Section中Supplementary View的种类。

  

三.UICollectionViewDelegateFlowLayout回调实现

UICollectionViewDelegateFlowLayout主要是负责显示的,比如Secion的大小、边距,Cell的大小边距,headerView的大小已经FooterView的大小,都是在UICollectionViewDelegateFlowLayout的相应协议的方法来实现的。接下来详细的介绍一下UICollectionViewDelegateFlowLayout协议中的方法。

    

1.同一个Section中同一种Cell(通过同一个Cell重用标示符获取的对象)可以有不同的尺寸,下面的代码是给Cell定制尺寸。代码的具体意思是第一个Section中的所有Cell的尺寸是(50,50)。 其余的时(60,60)。

 #pragma mark <UICollectionViewDelegateFlowLayout>
/**
* 改变Cell的尺寸
*/
- (CGSize)collectionView: (UICollectionView *)collectionView
layout: (UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath: (NSIndexPath *)indexPath{ if (indexPath.section == ) {
return CGSizeMake(, );
} return CGSizeMake(, );
}

2.改变Section的上下左右边距--UIEdgeInsetsMake(上, 左, 下, 右),逆时针旋转。第一个Section的上左下右的边距都是50, 其余的Section上左下右的边距是0。具体实现看如下代码:

 /**
* Section的上下左右边距--UIEdgeInsetsMake(上, 左, 下, 右);逆时针
*/
- (UIEdgeInsets)collectionView: (UICollectionView *)collectionView
layout: (UICollectionViewLayout*)collectionViewLayout
insetForSectionAtIndex: (NSInteger)section{ if (section == ) {
return UIEdgeInsetsMake(, , , );
}
return UIEdgeInsetsMake(, , , );
}

  

3.设置每个Cell的上下边距的回调如下所示,第一个Section的Cell上下边距是5.0f, 其余的为20.0f。

 /**
* Section中每个Cell的上下边距
*/
- (CGFloat)collectionView: (UICollectionView *)collectionView
layout: (UICollectionViewLayout*)collectionViewLayout
minimumLineSpacingForSectionAtIndex: (NSInteger)section{
if (section == ) {
return 5.0f;
}
return 20.0f;
}

4.设置Cell的左右边距,第一个Section的Cell左右边距是5.0f, 其余的为20.0f。

 /**
* Section中每个Cell的左右边距
*/
- (CGFloat)collectionView: (UICollectionView *)collectionView
layout: (UICollectionViewLayout*)collectionViewLayout
minimumInteritemSpacingForSectionAtIndex: (NSInteger)section{
if (section == ) {
return 5.0f;
}
return 20.0f;
}

5.设置Header View和Footer View的大小的回调如下。

 /**
* headerView的大小
*/
- (CGSize)collectionView: (UICollectionView *)collectionView
layout: (UICollectionViewLayout*)collectionViewLayout
referenceSizeForHeaderInSection: (NSInteger)section{
return CGSizeMake(, );
} /**
* footerView的大小
*/
- (CGSize)collectionView: (UICollectionView *)collectionView
layout: (UICollectionViewLayout*)collectionViewLayout
referenceSizeForFooterInSection: (NSInteger)section{
return CGSizeMake(, );
}

上面的方法就是UICollectionViewDelegateFlowLayout中所有的方法了,负责布局显示的。

  

四、UICollectionViewDelegate回调实现

UICollectionViewDelegate中的代理方法主要是负责Cell的交互的,比如是否高亮,是否选,是否可编辑等,接下来要为大家详细的介绍UICollectionViewDelegate中的代理方法。

    

1.为了这部分的效果展示,我们需要对Cell添加一些控件,并且设置其Highlight和Selected的一些状态。为Cell添加上ImageView, Cell的高亮状态和非高亮状态对应的ImageView上的图片是不同的。再添加一个Button, 并为Button设置Selected和Default状态下的图片,Button的选中和默认状态由Cell的选中状态来定。Cell中改变ImageView的图片的代码如下所示,函数传入的参数是当前Cell的高亮状态,根据高亮状态来设置ImageView上的Image。(有的小伙伴会问为什么给ImageView在Default状态和Highlight下设置不同的图片,然后直接改变ImageView的高亮状态即可。你可以试一下,达不到预期的效果)

 - (void) changeHighLightWithBool: (BOOL) highlight{

     NSString *imageName = @"003.jpg";

     if (highlight) {
imageName = @"002.jpg";
} [_highlightImage setImage: [UIImage imageNamed:imageName]];
}

2.设置Cell可以高亮, 返回YES代表Cell可以高亮,返回NO代表Cell不可高亮。高亮就是触摸Cell时该Cell变为高亮状态,在代码中的反应就是Cell的Highligth属性变为YES。而触摸结束时,Cell的Highligth属性就变为NO。

 #pragma mark <UICollectionViewDelegate>

 /**
* Cell是否可以高亮
*/
- (BOOL)collectionView: (UICollectionView *)collectionView
shouldHighlightItemAtIndexPath: (NSIndexPath *)indexPath{ return YES; }

3.下面这个方法是自己写的,用来在界面上反应Cell的高亮状态。 ImageView在当前Cell高亮状态下和非高亮状态下所加载的图片不同,所以可以看出Cell高亮和非高亮。

 /**
* 根据高亮状态修改背景图片
*/
- (void) changeHighlightCellWithIndexPaht: (NSIndexPath *) indexPath{
//获取当前变化的Cell
CollectionViewCell *currentHighlightCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; [currentHighlightCell changeHighLightWithBool:currentHighlightCell.highlighted]; if (currentHighlightCell.highlighted == YES){ NSLog(@"第%ld个Section上第%ld个Cell变为高亮",indexPath.section ,indexPath.row);
return;
} if (currentHighlightCell.highlighted == NO){
NSLog(@"第%ld个Section上第%ld个Cell变为非高亮",indexPath.section ,indexPath.row);
} }

4.Cell从非高亮变为高亮状态时回调用下面的方法,为了反映Cell的高亮状态,我们去改变一下Cell上ImageView的图片。

 /**
* 如果Cell可以高亮,Cell变为高亮后调用该方法
*/
- (void)collectionView: (UICollectionView *)collectionView
didHighlightItemAtIndexPath: (NSIndexPath *)indexPath{ [self changeHighlightCellWithIndexPath:indexPath];
} /**
* 如果Cell可以高亮,Cell从高亮变为非高亮调用该方法
*/
- (void)collectionView: (UICollectionView *)collectionView
didUnhighlightItemAtIndexPath: (NSIndexPath *)indexPath{ [self changeHighlightCellWithIndexPath:indexPath]; }

5.设定Cell是否可选的回调如下所示,Cell被选中时该Cell的Selected为YES, 取消选中Selected为NO;

 /**
* Cell是否可以选中
*/
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}

6. 如果想让你的Cell支持多选,就需要设定一下CollectionView的allowsMultipleSelection属性,下面的代码是在ViewDidLoad中添加的,如下所示:

     //设置Cell多选
self.collectionView.allowsMultipleSelection = YES;

7.如果在多选状态下需要支持取消Cell的多选,那么就去执行下面的方法,并返回YES。就是支持在多选状态下取消选中状态。

 /**
* Cell多选时是否支持取消功能
*/
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}

8.下面这个方法是自己封装的,用来根据Cell的选中状态来改变Cell上Button的选中状态,具体代码实现如下:

 /**
* Cell根据Cell选中状态来改变Cell上Button按钮的状态
*/
- (void) changeSelectStateWithIndexPath: (NSIndexPath *) indexPath{
//获取当前变化的Cell
CollectionViewCell *currentSelecteCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath]; currentSelecteCell.selectButton.selected = currentSelecteCell.selected; if (currentSelecteCell.selected == YES){
NSLog(@"第%ld个Section上第%ld个Cell被选中了",indexPath.section ,indexPath.row);
return;
} if (currentSelecteCell.selected == NO){
//NSLog(@"第%ld个Section上第%ld个Cell取消选中",indexPath.section ,indexPath.row);
} }

9.在Cell选中和取消选中时都会调用上面的方法来改变Button的选中状态,下面是Cell在选中时以及取消选中时所调用的方法:

 /**
* Cell选中调用该方法
*/
- (void)collectionView: (UICollectionView *)collectionView
didSelectItemAtIndexPath: (NSIndexPath *)indexPath{ [self changeSelectStateWithIndexPath:indexPath];
} /**
* Cell取消选中调用该方法
*/
- (void)collectionView: (UICollectionView *)collectionView didDeselectItemAtIndexPath: (NSIndexPath *)indexPath{ [self changeSelectStateWithIndexPath:indexPath];
}

    

10.下方四个方法是Cell将要出现,Cell出现后,Supplementary View将要出现以及Supplementary View已经出现所调用的方法,具体信息请看下方代码实现:

 /**
* Cell将要出现的时候调用该方法
*/
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){
NSLog(@"第%ld个Section上第%ld个Cell将要出现",indexPath.section ,indexPath.row);
} /**
* Cell出现后调用该方法
*/
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"第%ld个Section上第%ld个Cell已经出现",indexPath.section ,indexPath.row);
} /**
* headerView或者footerView将要出现的时候调用该方法
*/
- (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){ NSLog(@"第%ld个Section上第%ld个扩展View将要出现",indexPath.section ,indexPath.row); } /**
* headerView或者footerView出现后调用该方法
*/
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath{ NSLog(@"第%ld个Section上第%ld个扩展View已经出现",indexPath.section ,indexPath.row); }

  

在UICollectionViewDelegate回调方法中还有三个回调方法是关于Cell编辑的,比如copy, past, cut等操作,具体代码就不在此赘述了。在Demo中给出了实现方式,主要涉及到UIPasteboard的操作,本篇博客的整体的Demo回分享到Github上,下方是Github上的分享链接,感兴趣的小伙伴可以进行Clone。

  

Github分享链接:https://github.com/lizelu/CollectionViewControllerDemo

iOS开发之窥探UICollectionViewController(二) --详解CollectionView各种回调的更多相关文章

  1. iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流

    在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,C ...

  2. iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流

    上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewControlle ...

  3. iOS开发之窥探UICollectionViewController(五) --一款炫酷的图片浏览组件

    本篇博客应该算的上CollectionView的高级应用了,从iOS开发之窥探UICollectionViewController(一)到今天的(五),可谓是由浅入深的窥探了一下UICollectio ...

  4. iOS开发--常用技巧 (MJRefresh详解)

         iOS开发--常用技巧 (MJRefresh详解) https://github.com/CoderMJLee/MJRefresh 下拉刷新01-默认 self.tableView.head ...

  5. iOS开发——多线程OC篇&多线程详解

    多线程详解 前面介绍了多线程的各种方式及其使用,这里补一点关于多线程的概念及相关技巧与使用,相信前面不懂的地方看了这里之后你就对多线程基本上没有什么问题了! 1——首先ios开发多线程中必须了解的概念 ...

  6. iOS开发——UI篇OC&transform详解

    transframe属性详解 1. transform属性 在OC中,通过transform属性可以修改对象的平移.缩放比例和旋转角度 常用的创建transform结构体方法分两大类 (1) 创建“基 ...

  7. iOS开发——屏幕适配篇&Masonry详解

    Masonry详解 前言 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-ip ...

  8. iOS开发——实用技术OC篇&事件处理详解

    事件处理详解 一:事件处理 事件处理常见属性: 事件类型 @property(nonatomic,readonly) UIEventType     type; @property(nonatomic ...

  9. ios开发——实战OC篇&FMDB详解

    FMDB详解 前一篇文章中我们介绍的SQLite的使用,在iOS中原生的SQLite API在使用上相当不友好. 于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.Plausibl ...

随机推荐

  1. ubuntu install eclipse-installer

    1. sudo mkdir /usr/eclipseInstaller 2. tar -zxvf eclipse-inst-linux64.tar.gz -C /usr/eclipseInstalle ...

  2. centos7 搭建nginx和tomcat集成

    一.安装jdk 1.yum install jdk 2.安装好了之后配置环境变量  在/etc/profile 二.创建项目运行目录 1. 我放在home目录  mkdir /web/webapps ...

  3. WIN32 窗口封装类实现

    CQWnd.h窗口类定义 // QWnd.h: interface for the CQWnd class. // ////////////////////////////////////////// ...

  4. K线图学习

    本博文(适合入门的股民朋友)内容来自网络,股市有风险,入市需谨慎 一.起源 K线图(Candlestick Charts)又称蜡烛图.日本线.阴阳线.棒线等,常用说法是“K线”,起源于日本十八世纪德川 ...

  5. win7 x64 vs2010 directShow开发环境配置

    近来工作需要,要用dirrectShow写一个视频播放的demo验证自己的想法.开发环境配置了好久都没有成功,最后终于弄完,现在记录下来,以后有同学遇到同样问题,可以以此法解决. windows SD ...

  6. hadoop生态圈介绍

    原文地址:大数据技术Hadoop入门理论系列之一----hadoop生态圈介绍   1. hadoop 生态概况 Hadoop是一个由Apache基金会所开发的分布式系统基础架构. 用户可以在不了解分 ...

  7. 不同类型的指针+1之后增加的大小不同(a,&a的地址是一样的,但意思不一样)

    main() { ]={,,,,}; ); printf(),*(ptr-)); } *(a+1)就是a[1],*(ptr-1)就是a[4], 执行结果是2, 5.&a+1不是首地址+1,系统 ...

  8. VS调试程序时一闪而过的问题-解决方法(网上搜集)

    在VS2012里的控制台应用程序在运行时,结果画面一闪而过,不管是用F5 还是用Ctrl + F5都是一样,导致无法看到结果. 网上有不少的办法,说是都是在程序最后加一个要程序暂停的语句或从控制台上获 ...

  9. ubuntu自定义分辨率

    首先说下为啥要专门敲个文章来说明这个问题,因为我最近入手了一台分辨率为3200*1800的高分辨率笔记本,但使用的时候发现现在的操作系统及其诸多软件对高分辨率屏幕的支持真的是太烂,字体发虚或者变得非常 ...

  10. Mpale 在汽车底盘悬架系统公差分析应用

    汽车底盘的作用是接受发动机的动力,使车轮转动,并保证汽车按驾驶员的操纵正常行驶.底盘包括传动系统.行驶系统.转向系统和制动系统这四大部分,通常,这四大系统也简称为传动系.行驶系.转向系和制动系.悬架是 ...