自定义的uicollectionviewlayout怎么定制footer
1个回答
展开全部
UICollectionView是iOS6引入的控件,而UIDynamicAnimator是iOS7上新添加的框架。
本文主要涵盖3部分:
一是简单概括UICollectionView的使用;二是自定义一个UICollectionViewLayout来实现不同的Collection布局;
三是在自定义UICollectionViewLayout的基础上添加UIDynamicAnimator。
1. 使用UICollectionView
因为UICollectionView在iOS6上就引入了,所以这里就简单的介绍下。在正式使用前,我们有必要对UICollectionView认识一下。
UICollectionView和UITableView有点类似,但又有不一样。从上图可以看出,组建一个UICollectionView不仅需要内容相关的对象,
如DataSource和Delegate,还需要布局相关的对象即UICollectionViewLayout。
Data Source:提供相关的data和view
Delegate: 实现点击/插入/删除等操作时需要的方法
Layout:提供布局view(如cell,supplementary,decoration view)需要的相关数据
熟悉UITableView的,对DataSource和Delegate应该比较亲切,他们的作用和在TableView里的完全一样。而UICollectionViewLayout是一个新的类,
他的作用就是控制所有view的显示。Layout会为每个view(如果需要显示),提供一个LayoutAttribute,通过LayoutAttribute,CollectionView就
知道如何去组织了。注意LayoutAttribute除了可以提供frame信息,还可以添加伪3D的信息和UIKit的动态信息。通过抽离布局信息,这样很好的维护了
模块间的独立性,而且也方便我们对layout进行重定义。理解这个框架图有助于理解CollectionView的渲染过程以及自定义Layout。
下面我们认识下COllectionView:
上图是UICollectionViewFlowLayout的一个布局,我们以此进行介绍:
Cell:如上每一个单元格就是一个cell,和UITableViewCell一样,你可以进行自定义,添加image,label等等
Supplementary view:图中的Header和Footer就是Supplementary view,
Decoration view: 图中没有显示,不过顾名思义可以理解为修饰的view,如背景之类。它和Supplemetary的区别在于,后者往往是和数据相关联的。
知道了这些,我们就可以实现一个简单的CollectionView了。
在storeboard里新建一个viewController,并在view上添加一个UICollectionView,collectionview的delegate和datasource都在SB里连接好。
为了简单,我们直接使用UICollectionViewFlowLayout:
红色和绿色的label所在处就代表header和footer,他们都是用supplementary来表示,中间的Imageview所在处代表一个cell。
代码里三者都进行了简单的继承自定义,注意给他们三者设置一个identifier,这样利于重用。
然后在代码里实现dataSource方法:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 2; } - (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section; { return 20; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { ZJCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ZJCell" forIndexPath:indexPath]; NSString *imgName = [NSString stringWithFormat:@"%d.JPG",indexPath.row]; cell.imageView.image = [UIImage imageNamed:imgName]; return cell; } - (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { ZJSupplementaryView *supplementaryView = nil; NSString *text = nil; if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { supplementaryView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"CLHeader" forIndexPath:indexPath]; text = [NSString stringWithFormat:@"Header %d",indexPath.section]; supplementaryView.backgroundColor = [UIColor darkGrayColor]; } else { supplementaryView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"CLFooter" forIndexPath:indexPath];; text = [NSString stringWithFormat:@"Footer %d",indexPath.section]; supplementaryView.backgroundColor = [UIColor lightGrayColor]; } supplementaryView.label.text = text; return supplementaryView; }
这样一个最简单的flow式的照片显示就实现了,成品如下:
2 自定义Layout
Layout类中,有3个方法是必定会被依次调用:
prepareLayout: 准备所有view的layoutAttribute信息
collectionViewContentSize: 计算contentsize,显然这一步得在prepare之后进行
layoutAttributesForElementsInRect: 返回在可见区域的view的layoutAttribute信息
此外,还有其他方法可能会被调用:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { } - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { } - (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind atIndexPath:(NSIndexPath *)indexPath { } - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { }
比如,如果没有Decoration view,那么相应的方法就可以不实现。
接下来我们要实现一个自定义的layout。官方文档CollectionViewPGforIOS中指出了需要自定义layout的情形:
简单的说,就是现有的类(UICollectionViewLayout和UICollectionViewFlowLayout)不能满足需要的情况下需要自定义。
下面我们来实现CollectionViewPGforIOS中的自定义的例子,如图:
文档中,已经详细的阐述了每一步需要做的事情,这里就不多说了。但是因为文档中对于实现细节没有涉及,因此这里主要还是围绕之前提到的3个方法来进行说明。
这里假设你已经看过文档,并且知道自定义所需要的步骤。还需要声明的是,文档中给出的图以及下文的文字说明都是竖状排列的,但是由于疏忽,实现的时候变成了横向。希望因此不会给你造成混淆。
前提还需要做的准备:
1 定义Layout的子类
@interface ZJCustomLayout : UICollectionViewLayout @property (nonatomic, weak) id customDataSource; @end
@interfaceZJCustomLayout ()
{
NSInteger numberOfColumn;//here in this Sample Column equals the section
}
@property (nonatomic) NSDictionary *layoutInformation;//存储所有view的layoutAttribute
@property (nonatomic) CGFloat maxWidth;//用于计算contentSize
@property (nonatomic) UIEdgeInsets insets;
@end
protocol是用来获取一些数据,稍后定义。在扩展中定义一些属性,用于存储信息。
2 定义LayoutAttribute的子类
@interface ZJCollectionViewLayoutAttributes : UICollectionViewLayoutAttributes @property (nonatomic) NSArray *children; @end @implementationZJCollectionViewLayoutAttributes - (BOOL)isEqual:(id)object { ZJCollectionViewLayoutAttributes *attribute = (ZJCollectionViewLayoutAttributes *)object; if ([self.children isEqualToArray:attribute.children]) { return [super isEqual:object]; } return NO; } @end
ZJCollectionViewLayoutAttribute就是每一个cell的属性,children表示当前cell所拥有的子cell。而isEqual是子类必须要重载的。
我们首先看一下,cell是如何布局的:
红色3是cell的最终位置。布局的时候,先把最后一列的cell依次加上,如红色1所示。
然后排前一列即第二列,先依次加上,这时最后的绿色cell有子cell,就把第三列的绿色cell位置更新。
最后排第一列,因为第一个cell有3个子cell,所以要空两个开始排列。这时最后一个绿色cell有子cell这时就又要调整第二列以及第三列的绿色cell。
这里cell调整的思路很清晰:先依次从上到下排列,然后再根据是否有子cell进行更新。
在实际实现中,我根据这样的思路,设计了类似的算法:
从后向前布局每一列,每一列的cell依次从上向下布局;
除最后一列的cell开始布局时,先查看当前列前一行的cell是否有子cell:有的话调整自己的位置
如果当前cell的位置进行了调整,那么调整自己子cell的位置
很显然,在初始化每个cell的layoutAttribute的时候,我们需要先知道每一个cell的子cell的情况,于是我们设计一个协议:
@protocol ZJCustomLayoutProtocol - (NSArray *)childrenAtIndexPath:(NSIndexPath *)indexPath; @end
这个和CollectionView的dataSource,delegate一样,由viewController来提供。
本文主要涵盖3部分:
一是简单概括UICollectionView的使用;二是自定义一个UICollectionViewLayout来实现不同的Collection布局;
三是在自定义UICollectionViewLayout的基础上添加UIDynamicAnimator。
1. 使用UICollectionView
因为UICollectionView在iOS6上就引入了,所以这里就简单的介绍下。在正式使用前,我们有必要对UICollectionView认识一下。
UICollectionView和UITableView有点类似,但又有不一样。从上图可以看出,组建一个UICollectionView不仅需要内容相关的对象,
如DataSource和Delegate,还需要布局相关的对象即UICollectionViewLayout。
Data Source:提供相关的data和view
Delegate: 实现点击/插入/删除等操作时需要的方法
Layout:提供布局view(如cell,supplementary,decoration view)需要的相关数据
熟悉UITableView的,对DataSource和Delegate应该比较亲切,他们的作用和在TableView里的完全一样。而UICollectionViewLayout是一个新的类,
他的作用就是控制所有view的显示。Layout会为每个view(如果需要显示),提供一个LayoutAttribute,通过LayoutAttribute,CollectionView就
知道如何去组织了。注意LayoutAttribute除了可以提供frame信息,还可以添加伪3D的信息和UIKit的动态信息。通过抽离布局信息,这样很好的维护了
模块间的独立性,而且也方便我们对layout进行重定义。理解这个框架图有助于理解CollectionView的渲染过程以及自定义Layout。
下面我们认识下COllectionView:
上图是UICollectionViewFlowLayout的一个布局,我们以此进行介绍:
Cell:如上每一个单元格就是一个cell,和UITableViewCell一样,你可以进行自定义,添加image,label等等
Supplementary view:图中的Header和Footer就是Supplementary view,
Decoration view: 图中没有显示,不过顾名思义可以理解为修饰的view,如背景之类。它和Supplemetary的区别在于,后者往往是和数据相关联的。
知道了这些,我们就可以实现一个简单的CollectionView了。
在storeboard里新建一个viewController,并在view上添加一个UICollectionView,collectionview的delegate和datasource都在SB里连接好。
为了简单,我们直接使用UICollectionViewFlowLayout:
红色和绿色的label所在处就代表header和footer,他们都是用supplementary来表示,中间的Imageview所在处代表一个cell。
代码里三者都进行了简单的继承自定义,注意给他们三者设置一个identifier,这样利于重用。
然后在代码里实现dataSource方法:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 2; } - (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section; { return 20; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { ZJCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ZJCell" forIndexPath:indexPath]; NSString *imgName = [NSString stringWithFormat:@"%d.JPG",indexPath.row]; cell.imageView.image = [UIImage imageNamed:imgName]; return cell; } - (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { ZJSupplementaryView *supplementaryView = nil; NSString *text = nil; if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { supplementaryView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"CLHeader" forIndexPath:indexPath]; text = [NSString stringWithFormat:@"Header %d",indexPath.section]; supplementaryView.backgroundColor = [UIColor darkGrayColor]; } else { supplementaryView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"CLFooter" forIndexPath:indexPath];; text = [NSString stringWithFormat:@"Footer %d",indexPath.section]; supplementaryView.backgroundColor = [UIColor lightGrayColor]; } supplementaryView.label.text = text; return supplementaryView; }
这样一个最简单的flow式的照片显示就实现了,成品如下:
2 自定义Layout
Layout类中,有3个方法是必定会被依次调用:
prepareLayout: 准备所有view的layoutAttribute信息
collectionViewContentSize: 计算contentsize,显然这一步得在prepare之后进行
layoutAttributesForElementsInRect: 返回在可见区域的view的layoutAttribute信息
此外,还有其他方法可能会被调用:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { } - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { } - (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind atIndexPath:(NSIndexPath *)indexPath { } - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { }
比如,如果没有Decoration view,那么相应的方法就可以不实现。
接下来我们要实现一个自定义的layout。官方文档CollectionViewPGforIOS中指出了需要自定义layout的情形:
简单的说,就是现有的类(UICollectionViewLayout和UICollectionViewFlowLayout)不能满足需要的情况下需要自定义。
下面我们来实现CollectionViewPGforIOS中的自定义的例子,如图:
文档中,已经详细的阐述了每一步需要做的事情,这里就不多说了。但是因为文档中对于实现细节没有涉及,因此这里主要还是围绕之前提到的3个方法来进行说明。
这里假设你已经看过文档,并且知道自定义所需要的步骤。还需要声明的是,文档中给出的图以及下文的文字说明都是竖状排列的,但是由于疏忽,实现的时候变成了横向。希望因此不会给你造成混淆。
前提还需要做的准备:
1 定义Layout的子类
@interface ZJCustomLayout : UICollectionViewLayout @property (nonatomic, weak) id customDataSource; @end
@interfaceZJCustomLayout ()
{
NSInteger numberOfColumn;//here in this Sample Column equals the section
}
@property (nonatomic) NSDictionary *layoutInformation;//存储所有view的layoutAttribute
@property (nonatomic) CGFloat maxWidth;//用于计算contentSize
@property (nonatomic) UIEdgeInsets insets;
@end
protocol是用来获取一些数据,稍后定义。在扩展中定义一些属性,用于存储信息。
2 定义LayoutAttribute的子类
@interface ZJCollectionViewLayoutAttributes : UICollectionViewLayoutAttributes @property (nonatomic) NSArray *children; @end @implementationZJCollectionViewLayoutAttributes - (BOOL)isEqual:(id)object { ZJCollectionViewLayoutAttributes *attribute = (ZJCollectionViewLayoutAttributes *)object; if ([self.children isEqualToArray:attribute.children]) { return [super isEqual:object]; } return NO; } @end
ZJCollectionViewLayoutAttribute就是每一个cell的属性,children表示当前cell所拥有的子cell。而isEqual是子类必须要重载的。
我们首先看一下,cell是如何布局的:
红色3是cell的最终位置。布局的时候,先把最后一列的cell依次加上,如红色1所示。
然后排前一列即第二列,先依次加上,这时最后的绿色cell有子cell,就把第三列的绿色cell位置更新。
最后排第一列,因为第一个cell有3个子cell,所以要空两个开始排列。这时最后一个绿色cell有子cell这时就又要调整第二列以及第三列的绿色cell。
这里cell调整的思路很清晰:先依次从上到下排列,然后再根据是否有子cell进行更新。
在实际实现中,我根据这样的思路,设计了类似的算法:
从后向前布局每一列,每一列的cell依次从上向下布局;
除最后一列的cell开始布局时,先查看当前列前一行的cell是否有子cell:有的话调整自己的位置
如果当前cell的位置进行了调整,那么调整自己子cell的位置
很显然,在初始化每个cell的layoutAttribute的时候,我们需要先知道每一个cell的子cell的情况,于是我们设计一个协议:
@protocol ZJCustomLayoutProtocol - (NSArray *)childrenAtIndexPath:(NSIndexPath *)indexPath; @end
这个和CollectionView的dataSource,delegate一样,由viewController来提供。
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询