UICollectionView的自定義佈局
阿新 • • 發佈:2019-02-13
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;
}