CollectionView 基础(一)创建系统collectionview

CollectionView同tableview很类似,但是比tableview强大。tableview只能支持行布局,但是collectionview可以把布局部分单独独立出来,随心所欲来布局文件。若是需要构建横向滑动列表、gridView等直线型布局,则使用UICollectionView+UICollectionViewFlowLayout搭建最合适;更复杂的布局,则可以使用UICollectionView+自定义Layout来实现。

 

首先,来了解一下UICollectionView工作流程:

QQ截图20160205112450.png

 

 

 

collectionveiw的工作流程如下:

 

当UICollectionView显示内容时,先从数据源获取cell,然后交给UICollectionView。再从UICollectionViewLayout获取对应的layout attributes(布局属性)。最后,根据每个cell对应的layout attributes(布局属性)来对cell进行布局,生成了最终的界面。而用户交互的时候,都是通过Delegate来进行交互。当然,上面只是布局cell,但是UICollectionView内部还有Supplementary View和Decoration View,也可以对其进行布局。

 

进行collectionview的开发可以通过如下的三种方式:

结合storyboard 开发系统默认的collectionview

结合storyboard + 自定义cell 来创建collectionview

完全纯代码创建collectionview

 

一、视图

UICollectionView上面显示内容的视图有三种Cell视图、Supplementary View和Decoration View。

Cell视图

CollectionView中主要的内容都是由它展示的,它是从数据源对象获取的。

Supplementary View

它展示了每一组当中的信息,与cell类似,它是从数据源方法当中获取的,但是与cell不同的是,它并不是强制需要的。例如flow layout当中的headers和footers就是可选的Supplementary View。

Decoration View

这个视图是一个装饰视图,它没有什么功能性,它不跟数据源有任何关系,它完全属于layout对象。

二、数据源和代理方法

1、注册cell或者Supplementary View使其重用

在使用数据源返回cell或者Supplementary View给collectionView之前,我们必须先要注册,用来进行重用。(在使用storyboard的时候通过设置cell identifier实际上就省略了手动register的步骤。但是在创建cell的时候复用identifier必须同storyboard中的一致,否则会crash报没有注册cell)

  • registerClass: forCellWithReuseIdentifier:

  • registerNib: forCellWithReuseIdentifier:

  • registerClass: forSupplementaryViewOfKind: withReuseIdentifier:

  • registerNib: forSupplementaryViewOfKind: withReuseIdentifier:

显而易见,前面两个方法是注册cell,后两个方法注册Supplementary View。其中,注册的方式有两种,第一种是直接注册class,它重用的时候会调用[[UICollectionView alloc] init]这样的初始化方法创建cell;另外一种是注册nib,它会自动加载nib文件。

注册的之后,我们如何重用? 
在数据源方法当中返回cell或者Supplementary view的方法当中通过dequeueReusableCellWithReuseIdentifier:forIndexPath: 或者 dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:方法获取cell或者Supplementary View。

2、数据源方法

数据源方法与UITableView类似,主要有:

  • numberOfSectionsInCollectionView:

  • collectionView: numberOfItemsInSection:

  • collectionView: cellForItemAtIndexPath:

  • collectionView: viewForSupplementaryElementOfKind: atIndexPath:

与UITableView不同的是多加了返回Supplementary view数据源方法。

3、代理方法

数据源为UICollectionView提供数据相关的内容,而代理则主要负责用户交互、与数据无关的视图外形。主要分成两部分:

1、通过调用代理方法,管理视图的选中、高亮

  • collectionView:shouldDeselectItemAtIndexPath:

  • collectionView:didSelectItemAtIndexPath:

  • collectionView:didDeselectItemAtIndexPath:

  • collectionView:shouldHighlightItemAtIndexPath:

  • collectionView:didHighlightItemAtIndexPath:

  • collectionView:didUnhighlightItemAtIndexPath:

2、长按cell,显示编辑菜单 与UITableView不同,用户长按cell时,UICollectionView可以显示编辑菜单。这个编辑菜单可以用来剪切、复制和粘贴cell。不过,要显示这个编辑菜单需要满足下面几个条件:

  • 代理对象必须实现下面三个方法: 
    collectionView:shouldShowMenuForItemAtIndexPath:

collectionView:canPerformAction:forItemAtIndexPath:withSender:

collectionView:performAction:forItemAtIndexPath:withSender:

  • 对于指定要编辑的cell,collectionView:shouldShowMenuForItemAtIndexPath:方法需要返回YES

  • collectionView:canPerformAction:forItemAtIndexPath:withSender: 方法中,对于剪切、复制、粘贴三种action至少有一个返回YES。其实,编辑菜单是有很多种action的,但是对于UICollectionView来说,它仅仅支持的剪切、复制、粘贴三个,所以说这个代理方法至少支持这三种的一种。 
    剪切、复制、粘贴的方法名是: 
    cut: 
    copy: 
    paste:

当上面的条件都满足了,用户就可以长按cell显示出编辑菜单,然后选择对应的action,从而就会回调delegate的collectionView:performAction:forItemAtIndexPath:withSender: 方法去做对应的事情。

当我们想控制编辑菜单仅仅显示复制和粘贴时,我们就可以在collectionView:canPerformAction:forItemAtIndexPath:withSender:方法中进行操作,具体请见下面代码:

 

1

2

3

4

5

6

- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender{

    if ([NSStringFromSelector(action) isEqualToString:@"copy:"]

        || [NSStringFromSelector(action) isEqualToString:@"paste:"])

        return YES;

    return NO;

}

三、UICollectionViewLayout

UICollectionViewLayout是通过UICollectionViewLayoutAttributes类来管理cell、Supplementary View和Decoration View的位置、transform、alpha、hidden等等。 
UICollectionViewLayout这个类只是一个基类,我们给UICollectionView使用的都是它的子类。系统为我们提供了一个最常用的layout为UICollectionViewFlowLayout,我们可以使用它制作grid view。当UICollectionViewLayout满足不了我们的需求时,我们可以子类化UICollectionViewLayout或者自定义layout,这个内容放到我下一篇当中。

UICollectionViewFlowLayout

使用UICollectionViewFlowLayout之前,我们来了解它内部常用的属性:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

//同一组当中,垂直方向:行与行之间的间距;水平方向:列与列之间的间距

@property (nonatomic) CGFloat minimumLineSpacing;

//垂直方向:同一行中的cell之间的间距;水平方向:同一列中,cell与cell之间的间距

@property (nonatomic) CGFloat minimumInteritemSpacing;

//每个cell统一尺寸

@property (nonatomic) CGSize itemSize;

//滑动反向,默认滑动方向是垂直方向滑动

@property (nonatomic) UICollectionViewScrollDirection scrollDirection;

//每一组头视图的尺寸。如果是垂直方向滑动,则只有高起作用;如果是水平方向滑动,则只有宽起作用。

@property (nonatomic) CGSize headerReferenceSize;

//每一组尾部视图的尺寸。如果是垂直方向滑动,则只有高起作用;如果是水平方向滑动,则只有宽起作用。

@property (nonatomic) CGSize footerReferenceSize;

//每一组的内容缩进

@property (nonatomic) UIEdgeInsets sectionInset;

注意:UICollectionViewFlowLayout内部的属性都是用来统一设置,若是统一设置无法满足需求,可以实现UICollectionViewDelegateFlowLayout代理方法,进行对应的设置。而后面内容我都以UICollectionViewFlowLayout的属性来叙述,请自行参照修改。

UICollectionViewFlowLayout在纵向滑动与横向滑动时,布局是不太一样的。

QQ截图20160205113024.png

由上图就可以看出来,UICollectionViewFlowLayout在布局时,会根据scrollDirection的值不同而产生不同的布局。

  • 垂直方向滑动:

Cell布局:UICollectionView的内容宽度与本身视图的宽度相等,并且是固定的。会根据sectionInset左右缩进、itemSize的宽度、minimumInteritemSpacing三个值来计算每一行cell数量。 
具体计算公式是: 
cellCount = (CollectionViewContentWidth-sectionInset.left-sectionInset.right+minimumInteritemSpacing)/(itemSize.width+minimumInteritemSpacing)CollectionViewContentWidth是UICollectionView的内容宽度,计算出来的cellCount进行四舍五入成一个整数就是每一行cell的数量。 
而每个cell之间实际的间隔值则是: 
realInteritemSpacing = (CollectionViewContentWidth-sectionInset.left-sectionInset.right-cellCount*itemSize.width)/(cellCount-1)
当每个cell大小确定、每一行cell的个数确定、每个cell之间的间距确定之后,UICollectionViewFlowLayout就可以计算出每一行cell的frame了。 
而如果同一组cell的个数,在水平方向的一行放不下去,则就会放入第二行,而这第二行的cell在垂直方向与第一行的cell相隔minimumLineSpacing。这样又确定了行与行之间的间距,那么这一组cell的布局就可以确定了。

头视图与尾部视图:根据headerReferenceSize和footerReferenceSize中的高来确定头部和尾部视图的高,它其实就是两个不同类型的Supplementary View。

  • 水平方向滑动:

Cell布局:水平方向的滑动内容的高与本身视图的高是相等的,并且是固定的。它的cell是从上到下进行布局的。会根据sectionInset上下缩进、itemSize的高度、minimumInteritemSpacing三个值来计算每一列放多少个cell,具体计算公式可以参照垂直方向滑动的公式。之后的逻辑和垂直方向滑动时一样,只是minimumLineSpacing现在是代表列与列之间的间距。

头视图与尾部视图:根据headerReferenceSize和footerReferenceSize中的宽来确定头部和尾部视图的宽。

首先介绍第一种方式,storyboard 创建系统cell,不自定义cell的方式

1. 创建demo工程,在storybord中拖拉viewcontroller,以备之后添加collectionview

2. 创建包含collectionview的viewcontroller并且添加关联

3. 为默认创建的viewcontroller添加Navigationbar 和 跳转用的button

    选中button,在其connections inspector选项中,将action选中并且拖拉出链接线到新创建的含有collectionview的viewcontroller中

 

4. 在新创建的的viewcontroller中添加入delegate和datasource的引用,以及对于在storyboard中的viewcontroller的引用,已经datasource方法

 

 

 

 

5. 为storyboard中的cell设置identifier

6. 在storyboar中为collectionview添加delegate和datasource的所属viewcontroller

 

 

 

6. 书写datasource方法,并且使用storyboar中设置的cell id来创建cell用于展示

最终就可以看到演示效果了

 

注: 这种系统方式的常见适用于较为简单的实现,在storyboard中可以通过自定义cell就可以实现了。但是如果是相对复杂的实现,那么就应当考虑纯代码自定义cell 和 layout配合使用以达到目的了。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值