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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章