UICollectionView控件的使用一般会在特殊的界面处理上,但是也有比较规矩的应用软件会用UICollectionView。例如效果如下的界面;
下面开始讲述我的界面是如何做的。
1.首先我会把界面分成5个section,这就需要上篇文章讲述的自定义UICollectionReusableView 和自定义自定义UICollectioncell相结合了。
2.每个section下的cell需要不同的布局样式,这个跟以前的uitableview的自定义cell是一毛一样的。
3.UICollectionViewFlowLayout对布局的定义(最重要的也是这个)
下面上代码:
//自定义的五个section
-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *resuableView;
//每一个section的headerview
if (indexPath.section == 0) {
if (kind == UICollectionElementKindSectionHeader) {
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"cycleHeader" forIndexPath:indexPath];
headerView.backgroundColor = QFWhiteColor;
[headerView addSubview:self.sdcycleScroll];
self.sdcycleScroll.sd_layout.spaceToSuperView(UIEdgeInsetsMake(0, 0, 0, 0));
resuableView = headerView;
}
else
{
return nil;
}
}
else
{
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView" forIndexPath:indexPath];
headerView.backgroundColor = QFWhiteColor;
//清空子view
[QFCommon removeAllSubViewsOnView:headerView];
if (indexPath.section == 1)
{
resuableView = headerView;
}
else
{
_mainModel = _mainList[indexPath.section];
//标题
UILabel *titleLable = [UILabel new];
titleLable.backgroundColor = QFClearColor;
titleLable.textColor = QFSectionTitleColor;
titleLable.font = QFUsualBody;
titleLable.textAlignment = NSTextAlignmentCenter;
titleLable.text = _mainModel.section.secction_chinses;
[headerView addSubview:titleLable];
//分割线
UILabel *sectionLine = [UILabel new];
sectionLine.backgroundColor = QFLineColor;
[headerView addSubview:sectionLine];
//英文
UILabel *englishLable = [UILabel new];
englishLable.backgroundColor = QFClearColor;
englishLable.textColor = QFSectionSubTitleColor;
englishLable.font = QFUsualLabel;
englishLable.textAlignment = NSTextAlignmentCenter;
englishLable.text = _mainModel.section.section_english;
[headerView addSubview:englishLable];
//布局约束
titleLable.sd_layout.leftSpaceToView(headerView,0).topSpaceToView(headerView,5).rightSpaceToView(headerView,0).heightIs(25);
sectionLine.sd_layout.topSpaceToView(titleLable,0).centerXEqualToView(headerView).widthIs(50).heightIs(1);
englishLable.sd_layout.leftSpaceToView(headerView,0).topSpaceToView(sectionLine,0).rightSpaceToView(headerView,0).heightIs(20);
resuableView = headerView;
}
}
return resuableView;
}
2.不同的cell
//每行3个方格的cell
//下面的多种cell
最后将自定义的layout代码上一下,这个也是最重要的。
#import "ForeverGuardFlowLayout.h"
//默认的边缘间距
static const UIEdgeInsets QFDefaultEdgeInsets = {10,10,10,10};
@interface ForeverGuardFlowLayout()
/** 存放所有cell的布局属性 */
@property (nonatomic, strong) NSMutableArray *attrsArray;
/** 存放所有列的当前高度 */
@property (nonatomic, strong) NSMutableArray *columnHeights;
/** 内容的高度 */
@property (nonatomic, assign) CGFloat contentHeight;
//布局进行到的section
@property (nonatomic, assign) NSInteger lastSection;
//布局到目前为止的长度
@property (nonatomic, assign) CGFloat loadHeight;
@end
@implementation ForeverGuardFlowLayout
#pragma mark-懒加载
-(NSMutableArray *)columnHeights
{
if (!_columnHeights) {
_columnHeights = [NSMutableArray array];
}
return _columnHeights;
}
- (NSMutableArray *)attrsArray
{
if (!_attrsArray) {
_attrsArray = [NSMutableArray array];
}
return _attrsArray;
}
#pragma mark -默认方法
/**
* 决定cell的排布
*/
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.attrsArray;
}
-(CGSize)collectionViewContentSize
{
return CGSizeMake(0, self.contentHeight + _wholeEdgeInsets.bottom);
}
#pragma mark-设置边框、间距这些常量
//全局边距的设定(不设定就按照默认值为(10,10,10,10)计算)
-(void)setWholeEdgeInsets:(UIEdgeInsets)wholeEdgeInsets
{
if (wholeEdgeInsets.left != QFDefaultEdgeInsets.left || wholeEdgeInsets.right != QFDefaultEdgeInsets.right || wholeEdgeInsets.top != QFDefaultEdgeInsets.top || wholeEdgeInsets.bottom != QFDefaultEdgeInsets.bottom ) {
_wholeEdgeInsets = wholeEdgeInsets;
}
else
{
_wholeEdgeInsets = QFDefaultEdgeInsets;
}
}
#pragma mark-关键的两个方法
-(void)prepareLayout
{
[super prepareLayout];
//防止_lastSection=0时无法对section=0布局,才对_lastSectiobn设置一个非0的数值
_lastSection = 10000;
//初始化常量
self.contentHeight = 0.0;
//清除以前计算的所有高度
[self.columnHeights removeAllObjects];
//获取第一行有几列
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
NSInteger firstColumnCount = [self.delegate foreverGuardFlowLayoutColumnCountWithIndexpath:indexPath];
//给第一行的高度做初始化
for (NSInteger i=0; i<firstColumnCount; i++) {
[self.columnHeights addObject:@(_wholeEdgeInsets.top)];
}
//清除所有的布局属性
[self.attrsArray removeAllObjects];
//开始创建每一个Cell的布局属性
NSInteger sectionNum = [self.collectionView numberOfSections];
for (NSInteger m = 0; m<sectionNum; m++) {
NSInteger rowNum = [self.collectionView numberOfItemsInSection:m];
for (NSInteger n = 0; n<rowNum; n++) {
//创建对应的Indexpath
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:n inSection:m];
// 获取indexPath位置cell对应的布局属性
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArray addObject:attrs];
}
}
}
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 创建布局属性
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//声明cell的位置和大小
CGFloat cellWidth,cellHeighth,cellX,cellY;
//初始化必要的变量
NSInteger destColumn = 0;
//先取出第一列的高度作为比较的初始值
CGFloat minColumnHeight = [self.columnHeights[0]floatValue];
/*******根据自定义协议回调方法取出在外声明的cell的相关数据********/
CGSize cellSize = [self.delegate foreverGuardFlowLayoutCellSizeWithIndexpath:indexPath];
CGFloat sectionHeight = [self.delegate foreverGuardFlowLayoutSectionHeightWithIndexpath:indexPath];
NSInteger sectionColumn = [self.delegate foreverGuardFlowLayoutColumnCountWithIndexpath:indexPath];
CGFloat columnMargin = [self.delegate foreverGuardFlowLayoutColumnMarginWithIndexpath:indexPath];
CGFloat rowMargin = [self.delegate foreverGuardFlowLayoutRowMarginWithIndexpath:indexPath];
//当前的section和row的数值
NSInteger currentSection = indexPath.section;
NSInteger currentRow = indexPath.row;
cellWidth = cellSize.width;
cellHeighth = cellSize.height;
//对cell开始布局
if (_lastSection == currentSection) {
//排放的位置(放到第几列)
destColumn = currentRow % sectionColumn;
//获取cell的X值
cellX = self.wholeEdgeInsets.left + destColumn * (cellWidth + columnMargin);
//获取cell的Y值
for (NSInteger i = 1; i < sectionColumn; i++) {
// 取得第i列的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
if (minColumnHeight > columnHeight) {
minColumnHeight = columnHeight;
}
}
cellY = minColumnHeight;
if (cellY != self.wholeEdgeInsets.top)
cellY += rowMargin;
if (currentRow < sectionColumn) {
cellY = _loadHeight;
}
attrs.frame = CGRectMake(cellX, cellY, cellWidth, cellHeighth);
}
else
{
//添加一个section然后再添加section下的第一个cell
_lastSection = currentSection;
cellX = self.wholeEdgeInsets.left;
for (NSInteger i = 1; i < sectionColumn; i++) {
// 取得第i列的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
if (minColumnHeight < columnHeight) {
minColumnHeight = columnHeight;
}
}
cellY = minColumnHeight;
cellY += rowMargin;
//添加section的header部分到布局属性数组里面
UICollectionViewLayoutAttributes *layoutAttributesHeader = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:indexPath];
layoutAttributesHeader.frame = CGRectMake(0, cellY, QFDEVICE_WIDTH, sectionHeight);
[self.attrsArray addObject:layoutAttributesHeader];
_loadHeight = cellY +sectionHeight;
attrs.frame = CGRectMake(cellX, _loadHeight, cellWidth, cellHeighth);
}
// 更新最短那列的高度
self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));
// 记录内容的高度
CGFloat columnHeight = [self.columnHeights[destColumn] floatValue];
if (self.contentHeight < columnHeight) {
self.contentHeight = columnHeight;
}
return attrs;
}