文档章节

iOS开发之UICollectionViewController系列(二) :详解CollectionView各种回调

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:17
字数 2831
阅读 1
收藏 0
点赞 0
评论 0

今天是大年三十,笔者在此给大家拜年了!原本此时是家人团聚在一起看春晚的时刻,无奈本人对春晚不是很感冒,所以接着上一篇文章进行扩展。


猴年快乐.jpg

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

Objective-C

 #pragma mark 

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

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

Objective-C

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

     return 30;
 }

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

Objective-C

  /**
   * 返回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的方法。

Objective-C

  /**
   * 注册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,具体代码如下所示:

Objective-C

  /**
   * 设置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)。

Objective-C

  #pragma mark  
  /**
   * 改变Cell的尺寸
   */
  - (CGSize)collectionView: (UICollectionView *)collectionView
                    layout: (UICollectionViewLayout*)collectionViewLayout
    sizeForItemAtIndexPath: (NSIndexPath *)indexPath{

      if (indexPath.section == 0) {
         return CGSizeMake(50, 50);
     }

     return CGSizeMake(60, 60);
 }

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

Objective-C

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

      if (section == 0) {
          return UIEdgeInsetsMake(50, 50, 50, 50);
     }
     return UIEdgeInsetsMake(0, 0, 0, 0);
 }

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

Objective-C

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

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

Objective-C

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

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

Objective-C

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

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

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

Objective-C

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

Objective-C

  #pragma mark

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

      return YES;

 }

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

Objective-C

  /**
   * 根据高亮状态修改背景图片
   */
  - (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的图片。

Objective-C

  /**
   * 如果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;

Objective-C

 /**
  * Cell是否可以选中
  */
 - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath{
     return YES;
 }
  1. 如果想让你的Cell支持多选,就需要设定一下CollectionView的allowsMultipleSelection属性,下面的代码是在ViewDidLoad中添加的,如下所示:

Objective-C

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

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

Objective-C

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

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

Objective-C

  /**
   * 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在选中时以及取消选中时所调用的方法:

Objective-C

  /**
   * 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已经出现所调用的方法,具体信息请看下方代码实现:

Objective-C

  /**
   * 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链接

参考文章:iOS开发之窥探UICollectionViewController(二) :详解CollectionView各种回调

本文转载自:http://www.jianshu.com/p/a53211fc59fe

共有 人打赏支持
AllenOR灵感
粉丝 10
博文 2139
码字总数 82983
作品 0
程序员
iOS | 伤人于无形:CGFloat

背景 公司群有同事反映APP在plus机型上存在展示错误,如下: 实际上我们期望的效果是: 让人不解的是:只有在plus机型上才出现这种展示错误,其余机型都是OK的。 开发阶段我用了各种机型来调...

无夜之星辰 ⋅ 06/16 ⋅ 0

史上第二走心的 iOS11 Drag & Drop 教程

2017.11.02 话不多说,先上效果图 世界上最大的男性交友网站有demo 一.Tips:你必须要知道的概念 1. Drag 和 Drop 是什么呢? 一种以图形展现的方式把数据从一个 app 移动或拷贝到另一个 ap...

si1ence ⋅ 2017/12/14 ⋅ 0

如何获取UICollectionView的某个Cell

可能你会遇这种情况:collectionView每个cell是屏幕大小,然后上面添加了tableview,tableview可以上拉加载更多,当上拉加载完数据后,我们可以2种方式更新UI,如下 但有时候在加载过程中,你会...

爱跑步爱旅游 ⋅ 05/15 ⋅ 0

iOS源码补完计划--AFNetworking(二)

目录 前言 AFNetworkReachabilityManager.h AFNetworkReachabilityManager.m API注释Demo 参考资料 前言 AFNetworking源码第二篇 主要看了看AFNetworkReachabilityManager的内容 作为一个辅助...

kirito_song ⋅ 05/16 ⋅ 0

iOS UIWebView 使用大全

一、UIWebView的基础使用 以上是IOS中UIWebView的基础使用要点详解,接下来一些UIWebView的常用注意点。 二、IOS中UIWebView常用注意点: 1、与UIWebView进行交互,调用web页面中的需要传参的...

朝雨晚风 ⋅ 2016/08/15 ⋅ 0

开发微信H5视频秀项目遇到的坑

介绍 手头上正好有个项目,需要做一个微信端H5视频秀的一个项目,想想好像挺简单的,由两个视频组成,播放完第一个视频后点击按钮继而播放第二个视频。好了,结果微信的坑TM的多 问题排查 自...

🚲Allen ⋅ 05/18 ⋅ 0

阿里腾讯百度头条美团iOS面试总结

阿里腾讯百度头条美团iOS面试总结 2018-05-30 15:24编辑: garace分类:程序人生来源:代码湾 互联网面试iOS 招聘信息: C++工程师 Cocos2d-x游戏客户端开发 iOS开发工程师 京东招聘iOS开发工...

garace ⋅ 05/30 ⋅ 0

iOS高仿QQ侧滑控件、下载框架、动画效果、扫一扫、颜色变化、K线图等源码

iOS精选源码 仿京东"加入购物车"转场动画(http://www.code4app.com/thread-28162-1-1.html) ColorTool(颜色转换)(http://www.code4app.com/thread-29256-1-1.html) Swift 专业版K线(http://w......

sunnyaigd ⋅ 04/17 ⋅ 0

iOS源码补完计划--AFNetworking 3.1.0源码研读

参拜一下AFNetworking的源码。 第四篇源码、暂时来看也是iOS方向的最后一篇、撸完准备趁着热乎撸一撸网络协议。 目录 准备工作 功能模块 AFURLSessionManager/AFHTTPSessionManager AFNetwo...

kirito_song ⋅ 05/25 ⋅ 0

Unity与IOS交互,调用IOS系统相机和相册

前面两篇总结了一下unity与android的简单交互和调用安卓系统相机和相册,比较蛋疼的是,后来发现不同的测试机上会有不同的bug。。。下阶段要一个一个的解决一下 今天总结一下与IOS的交互。这...

qq_32587659 ⋅ 05/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

收集自网络的wordpress 分页导航的代码教程(全网最全版)

wordpress 分页导航是用来切换文章的一个功能,添加了 wordpress 分页导航后,用户即可自由到达指定的页面数浏览分类文章,而这样的一个很简单功能却有很多朋友在用插件:WP-PageNavi,插件的...

Rhymo-Wu ⋅ 32分钟前 ⋅ 0

微服务 WildFly Swarm 入门

Hello World 就像前面章节中的其他框架一样,我们希望添加一些基本的 Hello-world 功能,然后在其上逐步添加更多的功能。让我们从在我们的项目中创建一个 HolaResources 开始。您可以使用您的...

woshixin ⋅ 39分钟前 ⋅ 0

Maven的安装和Eclipse的配置

1. 下载Maven 下载地址 2. 解压压缩包,放到自己习惯的硬盘中 此处我将其放到了 D:\Tools 目录下。 3. 配置环境变量 右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量。 在系统变量中新建,变...

影狼 ⋅ 47分钟前 ⋅ 0

python pip使用国内镜像的方法

国内源 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://......

良言 ⋅ 47分钟前 ⋅ 0

对于url变化的spa应该如何使用微信jssdk

使用vue单页面碰上微信jssdk config验证失败的坑。第一次成功 之后切换页面全部失败,找到了解决方法,第一次验证成功后保存验证信息 切换页面时验证信息直接拿来用,加一个wx.error() 失败时...

孙冠峰 ⋅ 52分钟前 ⋅ 0

Spring Cloud Gateway 一般集成

SCF发布,带来很多新东西,不过少了点教程,打开方式又和以前的不一样,比如这个SCG,压根就没有入门指导,所以这里写一个,以备后用。 一、集成 pom.xml <dependency> <groupI...

kut ⋅ 55分钟前 ⋅ 0

建造模式

《JAVA与模式》之建造模式

Cobbage ⋅ 今天 ⋅ 0

WePY框架开发的小程序如何在微信web开发者工具中运行起来

一、首先需要安装node.js,安装步骤如下: 首先下载安装包 https://nodejs.org/en/download/ 点击下载相应的zip版本 然后将文件夹解压到任意目录 比如我这里解压到了:C:\Program Files\node...

Helios51 ⋅ 今天 ⋅ 0

使用EnumSet 代替位域(32)

1、位域(Bit field):使用or 运算将几个常量合并到一个集合中 位操作,可以有效地执行 AND 、OR 这样的位操作 但是 位域比int 常量枚举缺点更多 2、java.util 包里面的EnumSet 类是有效的替...

职业搬砖20年 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部