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,如下所示:

1 #pragma mark <UICollectionViewDataSource>
2
3 /**
4 * 返回Section的个数
5 */
6 - (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
7 return 5;
8 }

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

1 /**
2 * 返回每个Section中Cell的个数
3 */
4 - (NSInteger)collectionView: (UICollectionView *)collectionView
5 numberOfItemsInSection: (NSInteger)section {
6
7 return 30;
8 }

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

 1 /**
2 * 返回Cell种类
3 */
4 - (UICollectionViewCell *)collectionView: (UICollectionView *)collectionView
5 cellForItemAtIndexPath: (NSIndexPath *)indexPath {
6
7 //通过Cell重用标示符来获取Cell
8 CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: reuseIdentifier
9 forIndexPath: indexPath];
10
11 return cell;
12 }

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的方法。

 1 /**
2 * 注册Header和FooterView
3 * 便于在UICollectionViewDataSource中使用
4 */
5 - (void) registerHeaderAndFooterView {
6 //注册headerView
7 //获取含有UICollectionReusableView的Nib文件。
8 UINib *headerNib = [UINib nibWithNibName: @"CollectionHeaderReusableView"
9 bundle: [NSBundle mainBundle]];
10
11 //注册重用View
12 [self.collectionView registerNib: headerNib
13 forSupplementaryViewOfKind: UICollectionElementKindSectionHeader
14 withReuseIdentifier: @"CollectionHeaderReusableView"];
15
16
17 //注册FooterView
18 UINib *footerNib = [UINib nibWithNibName: @"CollectionFooterReusableView"
19 bundle:[ NSBundle mainBundle]];
20
21 [self.collectionView registerNib: footerNib
22 forSupplementaryViewOfKind: UICollectionElementKindSectionFooter
23 withReuseIdentifier: @"CollectionFooterReusableView"];
24
25 }

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

 1 /**
2 * 设置Setion的Header和Footer(Supplementary View)
3 */
4 - (UICollectionReusableView *)collectionView: (UICollectionView *)collectionView
5 viewForSupplementaryElementOfKind: (NSString *)kind
6 atIndexPath: (NSIndexPath *)indexPath{
7
8 //设置SectionHeader
9 if ([kind isEqualToString: UICollectionElementKindSectionHeader]) {
10
11 UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderReusableView" forIndexPath:indexPath];
12
13 return view;
14 }
15
16 //设置SectionFooter
17 UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionFooterReusableView" forIndexPath:indexPath];
18 return view;
19
20 }

  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)。

 1 #pragma mark <UICollectionViewDelegateFlowLayout>
2 /**
3 * 改变Cell的尺寸
4 */
5 - (CGSize)collectionView: (UICollectionView *)collectionView
6 layout: (UICollectionViewLayout*)collectionViewLayout
7 sizeForItemAtIndexPath: (NSIndexPath *)indexPath{
8
9 if (indexPath.section == 0) {
10 return CGSizeMake(50, 50);
11 }
12
13 return CGSizeMake(60, 60);
14 }

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

 1 /**
2 * Section的上下左右边距--UIEdgeInsetsMake(上, 左, 下, 右);逆时针
3 */
4 - (UIEdgeInsets)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 insetForSectionAtIndex: (NSInteger)section{
7
8 if (section == 0) {
9 return UIEdgeInsetsMake(50, 50, 50, 50);
10 }
11 return UIEdgeInsetsMake(0, 0, 0, 0);
12 }

  

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

 1 /**
2 * Section中每个Cell的上下边距
3 */
4 - (CGFloat)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 minimumLineSpacingForSectionAtIndex: (NSInteger)section{
7 if (section == 0) {
8 return 5.0f;
9 }
10 return 20.0f;
11 }

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

 1 /**
2 * Section中每个Cell的左右边距
3 */
4 - (CGFloat)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 minimumInteritemSpacingForSectionAtIndex: (NSInteger)section{
7 if (section == 0) {
8 return 5.0f;
9 }
10 return 20.0f;
11 }

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

 1 /**
2 * headerView的大小
3 */
4 - (CGSize)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 referenceSizeForHeaderInSection: (NSInteger)section{
7 return CGSizeMake(200, 50);
8 }
9
10 /**
11 * footerView的大小
12 */
13 - (CGSize)collectionView: (UICollectionView *)collectionView
14 layout: (UICollectionViewLayout*)collectionViewLayout
15 referenceSizeForFooterInSection: (NSInteger)section{
16 return CGSizeMake(200, 50);
17 }

上面的方法就是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的高亮状态即可。你可以试一下,达不到预期的效果)

 1 - (void) changeHighLightWithBool: (BOOL) highlight{
2
3 NSString *imageName = @"003.jpg";
4
5 if (highlight) {
6 imageName = @"002.jpg";
7 }
8
9 [_highlightImage setImage: [UIImage imageNamed:imageName]];
10 }

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

 1 #pragma mark <UICollectionViewDelegate>
2
3 /**
4 * Cell是否可以高亮
5 */
6 - (BOOL)collectionView: (UICollectionView *)collectionView
7 shouldHighlightItemAtIndexPath: (NSIndexPath *)indexPath{
8
9 return YES;
10
11 }

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

 1 /**
2 * 根据高亮状态修改背景图片
3 */
4 - (void) changeHighlightCellWithIndexPaht: (NSIndexPath *) indexPath{
5 //获取当前变化的Cell
6 CollectionViewCell *currentHighlightCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
7
8 [currentHighlightCell changeHighLightWithBool:currentHighlightCell.highlighted];
9
10 if (currentHighlightCell.highlighted == YES){
11
12 NSLog(@"第%ld个Section上第%ld个Cell变为高亮",indexPath.section ,indexPath.row);
13 return;
14 }
15
16 if (currentHighlightCell.highlighted == NO){
17 NSLog(@"第%ld个Section上第%ld个Cell变为非高亮",indexPath.section ,indexPath.row);
18 }
19
20
21 }

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

 1 /**
2 * 如果Cell可以高亮,Cell变为高亮后调用该方法
3 */
4 - (void)collectionView: (UICollectionView *)collectionView
5 didHighlightItemAtIndexPath: (NSIndexPath *)indexPath{
6
7 [self changeHighlightCellWithIndexPath:indexPath];
8 }
9
10
11 /**
12 * 如果Cell可以高亮,Cell从高亮变为非高亮调用该方法
13 */
14 - (void)collectionView: (UICollectionView *)collectionView
15 didUnhighlightItemAtIndexPath: (NSIndexPath *)indexPath{
16
17 [self changeHighlightCellWithIndexPath:indexPath];
18
19 }

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

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

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

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

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

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

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

 1 /**
2 * Cell根据Cell选中状态来改变Cell上Button按钮的状态
3 */
4 - (void) changeSelectStateWithIndexPath: (NSIndexPath *) indexPath{
5 //获取当前变化的Cell
6 CollectionViewCell *currentSelecteCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
7
8 currentSelecteCell.selectButton.selected = currentSelecteCell.selected;
9
10 if (currentSelecteCell.selected == YES){
11 NSLog(@"第%ld个Section上第%ld个Cell被选中了",indexPath.section ,indexPath.row);
12 return;
13 }
14
15 if (currentSelecteCell.selected == NO){
16 //NSLog(@"第%ld个Section上第%ld个Cell取消选中",indexPath.section ,indexPath.row);
17 }
18
19 }

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

 1 /**
2 * Cell选中调用该方法
3 */
4 - (void)collectionView: (UICollectionView *)collectionView
5 didSelectItemAtIndexPath: (NSIndexPath *)indexPath{
6
7 [self changeSelectStateWithIndexPath:indexPath];
8 }
9
10 /**
11 * Cell取消选中调用该方法
12 */
13 - (void)collectionView: (UICollectionView *)collectionView didDeselectItemAtIndexPath: (NSIndexPath *)indexPath{
14
15 [self changeSelectStateWithIndexPath:indexPath];
16 }

    

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

 1 /**
2 * Cell将要出现的时候调用该方法
3 */
4 - (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){
5 NSLog(@"第%ld个Section上第%ld个Cell将要出现",indexPath.section ,indexPath.row);
6 }
7
8 /**
9 * Cell出现后调用该方法
10 */
11 - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{
12 NSLog(@"第%ld个Section上第%ld个Cell已经出现",indexPath.section ,indexPath.row);
13 }
14
15
16 /**
17 * headerView或者footerView将要出现的时候调用该方法
18 */
19 - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){
20
21 NSLog(@"第%ld个Section上第%ld个扩展View将要出现",indexPath.section ,indexPath.row);
22
23 }
24
25 /**
26 * headerView或者footerView出现后调用该方法
27 */
28 - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath{
29
30 NSLog(@"第%ld个Section上第%ld个扩展View已经出现",indexPath.section ,indexPath.row);
31
32 }

  

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

  

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

作者:青玉伏案 
出处:http://www.cnblogs.com/ludashi/ 
本文版权归作者和共博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 
如果文中有什么错误,欢迎指出。以免更多的人被误导。

 
 

iOS UICollectionView(转二)的更多相关文章

  1. iOS UICollectionView之二(垂直滚动)

    #import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @pr ...

  2. 微信连WiFi关注公众号流程更新 解决ios微信扫描二维码不关注就能上网的问题

    前几天鼓捣了一下微信连WiFi功能,设置还蛮简单的,但ytkah发现如果是ios版微信扫描微信连WiFi生成的二维码不用关注公众号就可以直接上网了,而安卓版需要关注公众号才能上网,这样就少了很多ios ...

  3. XMPPFrameWork IOS 开发(二)- xcode配置

    原始地址:XMPPFrameWork IOS 开发(二) 译文地址:   Getting started using XMPPFramework on iOS 介绍 ios上的XMPPFramewor ...

  4. 【HELLO WAKA】WAKA iOS客户端 之二 架构设计与实现篇

    上一篇主要做了MAKA APP的需求分析,功能结构分解,架构分析,API分析,API数据结构分析. 这篇主要讲如何从零做iOS应用架构. 全系列 [HELLO WAKA]WAKA iOS客户端 之一 ...

  5. iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...

  6. 苹果IOS内购二次验证返回state为21002的坑

    项目是三四年前的老项目,之前有IOS内购二次验证的接口,貌似很久都没用了,然而最近IOS的妹子说接口用不了,让我看看啥问题.接口流程时很简单的,就是前端IOS在购买成功之后,接收到receipt后进行 ...

  7. iOS UICollectionView 长按移动cell

    ref:http://www.jianshu.com/p/31d07bf32d62 iOS 9之后: 示例如下 效果 前言: 看完你可以学到哪些呢? 就是文章标题那么多, 只有那么多. . 手残效果图 ...

  8. iOS UICollectionView(转三)

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

  9. iOS UICollectionView(转一) XIB+纯代码创建:cell,头脚视图 cell间距

    之前用CollectionViewController只是皮毛,一些iOS从入门到精通的书上也是泛泛而谈.这几天好好的搞了搞苹果的开发文档上CollectionViewController的内容,亲身 ...

随机推荐

  1. .net core 支付宝,微信支付 二

    源码: https://github.com/aspros-luo/Qwerty.Payment/tree/develop 今天开始微信支付 微信支付坑比较多,支付流程也不太一样,微信支付需要先生成预 ...

  2. 开始python成长之路

    因为某种特殊原因很不幸的得了脱髓鞘 正要去实习 大展身手 甚至公司都选好了 可就在这个节骨眼..得了传说中的脱髓鞘.经过一年的修养 我决定还是要站起来 毕竟一生的时间很长 这一段时间 我都在玩游戏赚钱 ...

  3. SHA安全散列算法简析

    1 SHA算法简介 1.1 概述 SHA (Secure Hash Algorithm,译作安全散列算法) 是美国国家安全局 (NSA) 设计,美国国家标准与技术研究院(NIST) 发布的一系列密码散 ...

  4. android stdio 快捷键

    俗话说工欲善其事必先利其器,先熟悉快捷键是很有必要的                 IDE   按键                                                 ...

  5. Web Api 2.0中使用Swagger生成Api文档的2个小Tips

    当Web Api 2.0使用OAuth2授权时,如何在Swagger中添加Authorization请求头? Swagger说明文档支持手动调用Api, 但是当Api使用OAuth2授权时,由于没有地 ...

  6. openstack pike 使用 openvswitch + vxlan

    # openstack pike 使用 openvswitch + vxlan# openstack pike linuxbridge-agent 换为 openvswitch-agent #open ...

  7. Sublime text3 代码格式化插件

    使用 Sublime text 3 格式化HTML代码,需要安装插件,具体安装步骤如下: 1. 打开菜单 -> 首选项(Perferences) -> 插件控制(Packpage Cont ...

  8. 洛谷 P3379 【模板】最近公共祖先(LCA)Tarjan离线

    题目链接:LCA tarjan离线 这道题目WA无数发,最后还是参考了大神的blog 谁会想到因为一个输入外挂WA呢 大概是我的挂是假挂吧...orz(其实加上外挂,速度提升很多) 用链式前向星保存边 ...

  9. angularjs 给封装的模态框元素传值,和实现兄弟传值

    本例实现封装的元素所放的位置不同,而选择不同的传值,这里举例封装了bootstrap模态框,以后也方便大家去直接使用.方法举例如下:首先主页调用css/js有: <link rel=" ...

  10. 矩阵的奇异值分解(SVD)(理论)

    矩阵的奇异值分解(Singular Value Decomposition,SVD)是数值计算中的精彩之处,在其它数学领域和机器学习领域得到了广泛的应用,如矩阵的广义逆,主分成分析(PCA),自然语言 ...