(轉(zhuǎn)) iOS開發(fā)之UICollectionViewController系列(二) :詳解CollectionView各種回調(diào)

UICollectionView的布局是可以自己定義的,在這篇博客中先在上篇博客的基礎(chǔ)上進(jìn)行擴(kuò)充,我們先使用UICollectionViewFlowLayout,然后好好的介紹一下UICollectionView的一些回調(diào)方法,主要包括UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,UICollectionViewDelegate相關(guān)回調(diào)方法,并通過實(shí)例來介紹每個(gè)回調(diào)的用法。并且給每個(gè)Section添加定制的Header和Footer,好廢話少說進(jìn)入今天的正題。
一、Demo總覽
下圖是本篇博客中Demo的最終運(yùn)行效果,下面是我們要做的事情:

  1. 給每個(gè)Section添加自定義的重用Header和Footer
    2.調(diào)整第一個(gè)Section的上左下右的邊距(UIEdgeInsets)
    3.給UICollectioinView設(shè)置多選
    4.處理Cell的高亮事件
    5.處理Cell的選中事件
    6.調(diào)整Cell的上下左右邊距
    7.對Cell進(jìn)行編輯



    二、UICollectionViewDataSource介紹
    1、在UICollectionViewDataSource回調(diào)方法中有一個(gè)返回Section數(shù)量的方法,如下所示,該方法和UITableView中的用法一致。在這兒我們返回5個(gè)Section,如下所示:

Objective-C

 #pragma mark 
 
 /**
  * 返回Section的個(gè)數(shù)
  */
 - (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
     return 5;
 }

2、在UICollectionViewDataSource的回調(diào)方法中,還有一個(gè)是返回每個(gè)Section中Cell的數(shù)量的方法,在這我們返回30個(gè)Cell, 如下代碼所示:

Objective-C

 /**
  * 返回每個(gè)Section中Cell的個(gè)數(shù)
  */
 - (NSInteger)collectionView: (UICollectionView *)collectionView
      numberOfItemsInSection: (NSInteger)section {
 
     return 30;
 }

3、在UICollectionViewDataSource還有一個(gè)必須實(shí)現(xiàn)的方法, 就是選擇我們CollectionView中所使用的Cell, 在這里我們所使用的Cell是在Storyboard上實(shí)現(xiàn)的,所以不需要在我們的代碼中注冊Cell, 之間使用重用標(biāo)示符就可以獲取Cell的對象,如下所示:

Objective-C

  /**
   * 返回Cell種類
   */
  - (UICollectionViewCell *)collectionView: (UICollectionView *)collectionView
                    cellForItemAtIndexPath: (NSIndexPath *)indexPath {
 
      //通過Cell重用標(biāo)示符來獲取Cell
      CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: reuseIdentifier
                                                                           forIndexPath: indexPath];
 
     return cell;
 }

4、在UICollectionViewDataSource方法中有一個(gè)可選的方法就是為我們的Section添加Supplementary View(追加視圖),下面是添Supplementary View(追加視圖)的步驟。在UICollectionView中的Section中我們可以為其增加Header View和Footer View, 也就是官方文檔上提到的Supplementary View(追加視圖)。追加視圖是可以重用的,也就是UICollectionReusableView。我們可以創(chuàng)建兩個(gè)UICollectionReusableView的子類,一個(gè)是Header View, 另一個(gè)是Footer View。
(1)創(chuàng)建UICollectionReusableView
追加視圖可以在Storyboard上添加,然后設(shè)置重用標(biāo)示符,在代碼中使用即可。這里我們是從xib文件來加載的Supplementary View, 先創(chuàng)建兩個(gè)UICollectionReusableView子類,在創(chuàng)建該子類的同時(shí)創(chuàng)建相應(yīng)的xib文件,如下所示:



創(chuàng)建Header View和Footer View的UICollectionReusableView,創(chuàng)建后的文件目錄如下:



(2) 因?yàn)槲覀兪菑膞ib文件中加載的UICollectionReusableView,所以需要在相應(yīng)的UICollectionView上進(jìn)行注冊。如果你是使用的Storyboard, 只需要在Storyboard中指定重用標(biāo)示符即可。下面的代碼就是在ViewDidLoad中調(diào)用注冊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中的設(shè)置Supplementary View的方法中通過Header View和Footer View的重用標(biāo)示符來為我們的Section設(shè)置Supplementary View,具體代碼如下所示:

Objective-C

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

UICollectionViewDataSource中的四個(gè)方法在上面都進(jìn)行了實(shí)現(xiàn),UICollectionViewDataSource主要是負(fù)責(zé)加載數(shù)據(jù)源的,包括Section的個(gè)數(shù),每個(gè)Section中Cell的個(gè)數(shù),每個(gè)Section中Supplementary View的種類。
三.UICollectionViewDelegateFlowLayout回調(diào)實(shí)現(xiàn)
UICollectionViewDelegateFlowLayout主要是負(fù)責(zé)顯示的,比如Secion的大小、邊距,Cell的大小邊距,headerView的大小已經(jīng)FooterView的大小,都是在UICollectionViewDelegateFlowLayout的相應(yīng)協(xié)議的方法來實(shí)現(xiàn)的。接下來詳細(xì)的介紹一下UICollectionViewDelegateFlowLayout協(xié)議中的方法。
1.同一個(gè)Section中同一種Cell(通過同一個(gè)Cell重用標(biāo)示符獲取的對象)可以有不同的尺寸,下面的代碼是給Cell定制尺寸。代碼的具體意思是第一個(gè)Section中的所有Cell的尺寸是(50,50)。 其余的時(shí)(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(上, 左, 下, 右),逆時(shí)針旋轉(zhuǎn)。第一個(gè)Section的上左下右的邊距都是50, 其余的Section上左下右的邊距是0。具體實(shí)現(xiàn)看如下代碼:

Objective-C

  /**
   * Section的上下左右邊距--UIEdgeInsetsMake(上, 左, 下, 右);逆時(shí)針
   */
  - (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.設(shè)置每個(gè)Cell的上下邊距的回調(diào)如下所示,第一個(gè)Section的Cell上下邊距是5.0f, 其余的為20.0f。

Objective-C

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

4.設(shè)置Cell的左右邊距,第一個(gè)Section的Cell左右邊距是5.0f, 其余的為20.0f。

Objective-C

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

5.設(shè)置Header View和Footer View的大小的回調(diào)如下。

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中所有的方法了,負(fù)責(zé)布局顯示的。
四、UICollectionViewDelegate回調(diào)實(shí)現(xiàn)
UICollectionViewDelegate中的代理方法主要是負(fù)責(zé)Cell的交互的,比如是否高亮,是否選,是否可編輯等,接下來要為大家詳細(xì)的介紹UICollectionViewDelegate中的代理方法。
1.為了這部分的效果展示,我們需要對Cell添加一些控件,并且設(shè)置其Highlight和Selected的一些狀態(tài)。為Cell添加上ImageView, Cell的高亮狀態(tài)和非高亮狀態(tài)對應(yīng)的ImageView上的圖片是不同的。再添加一個(gè)Button, 并為Button設(shè)置Selected和Default狀態(tài)下的圖片,Button的選中和默認(rèn)狀態(tài)由Cell的選中狀態(tài)來定。Cell中改變ImageView的圖片的代碼如下所示,函數(shù)傳入的參數(shù)是當(dāng)前Cell的高亮狀態(tài),根據(jù)高亮狀態(tài)來設(shè)置ImageView上的Image。(有的小伙伴會(huì)問為什么給ImageView在Default狀態(tài)和Highlight下設(shè)置不同的圖片,然后直接改變ImageView的高亮狀態(tài)即可。你可以試一下,達(dá)不到預(yù)期的效果)

Objective-C

  - (void) changeHighLightWithBool: (BOOL) highlight{
 
      NSString *imageName = @"003.jpg";
 
      if (highlight) {
          imageName = @"002.jpg";
      }
 
      [_highlightImage setImage: [UIImage imageNamed:imageName]];
 }

2.設(shè)置Cell可以高亮, 返回YES代表Cell可以高亮,返回NO代表Cell不可高亮。高亮就是觸摸Cell時(shí)該Cell變?yōu)楦吡翣顟B(tài),在代碼中的反應(yīng)就是Cell的Highligth屬性變?yōu)閅ES。而觸摸結(jié)束時(shí),Cell的Highligth屬性就變?yōu)镹O。

Objective-C

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

3.下面這個(gè)方法是自己寫的,用來在界面上反應(yīng)Cell的高亮狀態(tài)。 ImageView在當(dāng)前Cell高亮狀態(tài)下和非高亮狀態(tài)下所加載的圖片不同,所以可以看出Cell高亮和非高亮。

Objective-C

  /**
   * 根據(jù)高亮狀態(tài)修改背景圖片
   */
  - (void) changeHighlightCellWithIndexPaht: (NSIndexPath *) indexPath{
      //獲取當(dāng)前變化的Cell
      CollectionViewCell *currentHighlightCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
 
      [currentHighlightCell changeHighLightWithBool:currentHighlightCell.highlighted];
 
     if (currentHighlightCell.highlighted == YES){
 
         NSLog(@"第%ld個(gè)Section上第%ld個(gè)Cell變?yōu)楦吡?,indexPath.section ,indexPath.row);
         return;
     }
 
     if (currentHighlightCell.highlighted == NO){
         NSLog(@"第%ld個(gè)Section上第%ld個(gè)Cell變?yōu)榉歉吡?,indexPath.section ,indexPath.row);
     }
 
 }

4.Cell從非高亮變?yōu)楦吡翣顟B(tài)時(shí)回調(diào)用下面的方法,為了反映Cell的高亮狀態(tài),我們?nèi)ジ淖円幌翪ell上ImageView的圖片。

Objective-C


  /**
   * 如果Cell可以高亮,Cell變?yōu)楦吡梁笳{(diào)用該方法
   */
  - (void)collectionView: (UICollectionView *)collectionView
  didHighlightItemAtIndexPath: (NSIndexPath *)indexPath{
 
      [self changeHighlightCellWithIndexPath:indexPath];
  }
 
 /**
  * 如果Cell可以高亮,Cell從高亮變?yōu)榉歉吡琳{(diào)用該方法
  */
 - (void)collectionView: (UICollectionView *)collectionView
 didUnhighlightItemAtIndexPath: (NSIndexPath *)indexPath{
 
     [self changeHighlightCellWithIndexPath:indexPath];
 
 }

5.設(shè)定Cell是否可選的回調(diào)如下所示,Cell被選中時(shí)該Cell的Selected為YES, 取消選中Selected為NO;

Objective-C

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

Objective-C

     //設(shè)置Cell多選
     self.collectionView.allowsMultipleSelection = YES;

7.如果在多選狀態(tài)下需要支持取消Cell的多選,那么就去執(zhí)行下面的方法,并返回YES。就是支持在多選狀態(tài)下取消選中狀態(tài)。

Objective-C

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

8.下面這個(gè)方法是自己封裝的,用來根據(jù)Cell的選中狀態(tài)來改變Cell上Button的選中狀態(tài),具體代碼實(shí)現(xiàn)如下:

Objective-C

  /**
   * Cell根據(jù)Cell選中狀態(tài)來改變Cell上Button按鈕的狀態(tài)
   */
  - (void) changeSelectStateWithIndexPath: (NSIndexPath *) indexPath{
      //獲取當(dāng)前變化的Cell
      CollectionViewCell *currentSelecteCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
 
      currentSelecteCell.selectButton.selected = currentSelecteCell.selected;
 
     if (currentSelecteCell.selected == YES){
         NSLog(@"第%ld個(gè)Section上第%ld個(gè)Cell被選中了",indexPath.section ,indexPath.row);
         return;
     }
 
     if (currentSelecteCell.selected == NO){
         //NSLog(@"第%ld個(gè)Section上第%ld個(gè)Cell取消選中",indexPath.section ,indexPath.row);
     }
 
 }

9.在Cell選中和取消選中時(shí)都會(huì)調(diào)用上面的方法來改變Button的選中狀態(tài),下面是Cell在選中時(shí)以及取消選中時(shí)所調(diào)用的方法:

Objective-C

  /**
   * Cell選中調(diào)用該方法
   */
  - (void)collectionView: (UICollectionView *)collectionView
  didSelectItemAtIndexPath: (NSIndexPath *)indexPath{
 
      [self changeSelectStateWithIndexPath:indexPath];
  }
 
 /**
  * Cell取消選中調(diào)用該方法
  */
 - (void)collectionView: (UICollectionView *)collectionView didDeselectItemAtIndexPath: (NSIndexPath *)indexPath{
 
     [self changeSelectStateWithIndexPath:indexPath];
 }

10.下方四個(gè)方法是Cell將要出現(xiàn),Cell出現(xiàn)后,Supplementary View將要出現(xiàn)以及Supplementary View已經(jīng)出現(xiàn)所調(diào)用的方法,具體信息請看下方代碼實(shí)現(xiàn):

Objective-C

  /**
   * Cell將要出現(xiàn)的時(shí)候調(diào)用該方法
   */
  - (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){
      NSLog(@"第%ld個(gè)Section上第%ld個(gè)Cell將要出現(xiàn)",indexPath.section ,indexPath.row);
  }
 
  /**
   * Cell出現(xiàn)后調(diào)用該方法
  */
 - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{
     NSLog(@"第%ld個(gè)Section上第%ld個(gè)Cell已經(jīng)出現(xiàn)",indexPath.section ,indexPath.row);
 }
 
 /**
  * headerView或者footerView將要出現(xiàn)的時(shí)候調(diào)用該方法
  */
 - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){
 
     NSLog(@"第%ld個(gè)Section上第%ld個(gè)擴(kuò)展View將要出現(xiàn)",indexPath.section ,indexPath.row);
 
 }
 
 /**
  * headerView或者footerView出現(xiàn)后調(diào)用該方法
  */
 - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath{
 
     NSLog(@"第%ld個(gè)Section上第%ld個(gè)擴(kuò)展View已經(jīng)出現(xiàn)",indexPath.section ,indexPath.row);
 
 }

在UICollectionViewDelegate回調(diào)方法中還有三個(gè)回調(diào)方法是關(guān)于Cell編輯的,比如copy, past, cut等操作,具體代碼就不在此贅述了。在Demo中給出了實(shí)現(xiàn)方式,主要涉及到UIPasteboard的操作,本篇博客的整體的Demo回分享到Github上,下方是Github上的分享鏈接,感興趣的小伙伴可以進(jìn)行Clone。

Github鏈接

參考文章:iOS開發(fā)之窺探UICollectionViewController(二) :詳解CollectionView各種回調(diào)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift版本點(diǎn)擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 26,259評論 7 249
  • 最近將 UICollectionView 進(jìn)行了一個(gè)全面的學(xué)習(xí)及總結(jié),參考了網(wǎng)上大量的文章,把官方文檔進(jìn)行了大概翻...
    varlarzh閱讀 22,161評論 3 93
  • 概述 UICollectionView是iOS開發(fā)中最常用的UI控件之一,可以用它來管理一組有序的不同尺寸的視圖,...
    漸z閱讀 3,118評論 0 3
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,636評論 4 61
  • 夜瑯是網(wǎng)名,姓劉,貴州人,是從事建筑設(shè)計(jì)方面的資深工程師,60后,棋友們都叫他劉工。 劉工和老土是貴州老鄉(xiāng),是老棋...
    天山客閱讀 589評論 0 0

友情鏈接更多精彩內(nèi)容