1. 程式人生 > >UICollectionView的自定義佈局

UICollectionView的自定義佈局

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

兩組cell

//每行3個方格的cell

每行3個方格的cell

//下面的多種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;
}