iOS开发高级分享 — 窥探UICollectionViewController(二)

iOS开发高级分享 — 窥探UICollectionViewController(一)

详解CollectionView各类回调

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

1、Demo总览github

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

  1. 给每一个Section添加自定义的重用Header和Footer
  2. 调整第一个Section的上左下右的边距(UIEdgeInsets)
  3. 给UICollectioinView设置多选
  4. 处理Cell的高亮事件
  5. 处理Cell的选中事件
  6. 调整Cell的上下左右边距
  7. 对Cell进行编辑

2、UICollectionViewDataSource介绍

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

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

二、在UICollectionViewDataSource的回调方法中,还有一个是返回每一个Section中Cell的数量的方法,在这咱们返回30个Cell, 以下代码所示:布局

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

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

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 }
复制代码

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

(1)建立UICollectionReusableViewspa

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

建立Header View和Footer View的UICollectionReusableView,建立后的文件目录以下:code

(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中全部的方法了,负责布局显示的。

4、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 }
复制代码
  1. 若是想让你的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分享连接:github.com/lizelu/Coll…

做者:青玉伏案

出处:www.cnblogs.com/ludashi/

相关文章
相关标签/搜索