IOS 瀑布流UICollectionView實現

IOS 瀑布流UICollectionView實現


在實現瀑布流以前先來看看瀑布流的雛形(此方法的雛形 UICollectionView)數組

對於UICollectionView咱們有幾點注意事項dom

  • 它和tableView不同,ContentView的內容徹底須要咱們本身去添加。
  • 它與tableview相比,他的初始化須要FlowLayout而且大部分操做在其上。
  • UIcollectionView的實用性極強,雖然有時他並非最好的解決方案,可是它能夠很靈活的實現各類效果。

圖(一)ide

如圖,模擬器上展現的是不少方格,可是值得注意的是他們是有規則的。佈局

雖然看上去很整潔可是並不美觀。atom

咱們所說的要實現瀑布流就是要實現它的不整潔,可是規律(這裏我說的是規律)設計

正題

前面說了UIcollectionView的大部分操做在FlowLayout上,固然也包括格局部署。orm

爲了實現瀑布流咱們所要實現的即是改變他的格局部署。對象

在寫代碼前先肯定一下實現思想。

  • 須要什麼???
    • 首先咱們須要肯定瀑布流的顯示風格
    • 而後根據肯定好的風格進行總體設計
    • 最後經過細節的處理完善代碼
      • 咱們須要什麼樣的風格???
        • 咱們須要的是實現將上面圖片中的佈局改變爲不等高的效果
        • 說的俗一點就是像名字同樣,像瀑布流水同樣
      • 總體該如何設計???
        • 總體採用與上面圖片同樣的設計方法,每一個模塊都是一個cell
        • 確保最上面一行的cell的y值相同(美觀)
        • 確保不不會出現一列特別長,一列特別短的效果
      • 初步細節有哪些???
        • 由於每一個cell的height不一樣,因此咱們要考慮放置的順序應該是什麼
        • 精簡代碼(這是每一個項目必須注意的)

實現效果

代碼

下面是實現的代碼部分(不提供demo了 很簡單)blog

我在註釋中簡單介紹。圖片

---

複製代碼
//
//  ViewController.m
//  CX-瀑布流UIcollectionView實現
//
//  Created by ma c on 16/4/8.
//  Copyright © 2016年 bjsxt. All rights reserved.
//

#import "ViewController.h"
#import "CXCollectionViewCell.h"
#import "CXCollectionViewLayout.h"

static NSString * identifier = @"cellID";

@interface ViewController ()<UICollectionViewDataSource>
//所要展現的UICollectionView
@property (nonatomic, strong) UICollectionView * collectionView;

@end

@implementation ViewController

#pragma mark - <懶加載>
- (UICollectionView *)collectionView {
    if (!_collectionView) {
        //初始化咱們自定義的flowLayout
        CXCollectionViewLayout * flowLayout = [[CXCollectionViewLayout alloc]init];
        //初始化collectionView
        _collectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
        //設置數據源(collectionView的命根子)
        _collectionView.dataSource = self;
        //註冊咱們自定義的cell
        [_collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([CXCollectionViewCell class]) bundle:nil] forCellWithReuseIdentifier:identifier];
    }
    return _collectionView;
}


#pragma mark - <life>

- (void)viewDidLoad {
    [super viewDidLoad];
    //在self.view上添加---
    [self.view addSubview:self.collectionView];
}
#pragma mark - <UICollectionViewDataSource>
//這裏返回的是item的個數 返回100
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    
    return 100;
}
//這裏返回的是cell 咱們能夠在這裏進行一些簡單的操做
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    
    CXCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
    //爲了瀑布流的實現細節咱們添加的Label
    
    cell.label.text = [NSString stringWithFormat:@"%zd",indexPath.item];
    //cell的背景色
    cell.backgroundColor = [UIColor orangeColor];
    
    return cell;
}

@end
複製代碼

---

複製代碼
//
//  CXCollectionViewLayout.m
//  CX-瀑布流UIcollectionView實現
//
//  Created by ma c on 16/4/8.
//  Copyright © 2016年 bjsxt. All rights reserved.
//

#import "CXCollectionViewLayout.h"

//瀑布流的列數
static NSInteger CXcolumnCount = 3;
//瀑布流的內邊距
static UIEdgeInsets CXdefaultEdgeInsets = {20,15,10,15};
//cell的列間距
static NSInteger CXcolumnMagin = 10;
//cell的行間距
static NSInteger CXrowMagin = 10;

@interface CXCollectionViewLayout ()

//存放全部cell 的佈局屬性
@property (nonatomic, strong) NSMutableArray * CXattrsArray;
//縮放全部列的高度
@property (nonatomic, strong) NSMutableArray * CXcolumnHeights;

@end

@implementation CXCollectionViewLayout

#pragma mark - <懶加載>
- (NSMutableArray *)CXattrsArray{
    if (!_CXattrsArray) {
        _CXattrsArray = [NSMutableArray array];
    }
    return _CXattrsArray;
}

- (NSMutableArray *)CXcolumnHeights{
    if (!_CXcolumnHeights) {
        _CXcolumnHeights = [NSMutableArray array];
    }
    return _CXcolumnHeights;
}
#pragma mark - <準備佈局>
//準備佈局(佈局前自動執行)
- (void) prepareLayout{
    //重寫此方法必定要記得super
    [super prepareLayout];
    
    //在實際操做中咱們的數據並不會固定不變的,所以咱們每次佈局前最好要清空以前存儲的屬性
    //清空存放全部列的高度
    //清空存放全部cell的不去屬性
    [self.CXcolumnHeights removeAllObjects];
    [self.CXattrsArray removeAllObjects];
    //首先爲第一行的cell附高度
    for (NSInteger i = 0; i < CXcolumnCount; i ++) {
        //數組裏只能存放對象
        [self.CXcolumnHeights addObject:@(CXdefaultEdgeInsets.top)];
    }
    //下面開始建立每個cell的佈局屬性 而且添加到存儲cell佈局屬性的數組中
    //cell總個數 由於這裏只要一個section
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (NSInteger i = 0; i < count; i ++) {
        // 建立位置 即indexPath
        NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        //獲取indexPath對應的cell佈局屬性
        UICollectionViewLayoutAttributes * attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        //把獲取到的佈局屬性添加到數組中
        [self.CXattrsArray addObject:attributes];
    }
    //準備佈局的工做到這裏就結束了
}
//返回全部cell佈局屬性 及總體cell 的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
    return self.CXattrsArray;
}
//返回cell 的佈局屬性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    //建立佈局屬性
    UICollectionViewLayoutAttributes * CXattributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    //獲取collectionView 的寬
    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
    //下面的一部分是獲取cell的frame(佈局屬性)
    CGFloat width;
    CGFloat height;
    CGFloat X;
    CGFloat Y;
    //獲取width
    width = (collectionViewWidth - CXdefaultEdgeInsets.left - CXdefaultEdgeInsets.right - (CXcolumnCount - 1) * CXcolumnMagin) / CXcolumnCount;
    //獲取height
    //在實際開發中heigh並非真正的隨機 而是根據數據來決定height 在這裏展現初步的介紹其原理 所以採用大於100小於150的隨機數
    height = 100 + arc4random_uniform(50);
    //獲取X (瀑布流的實現重點就在cell的X,Y值獲取)
    //設置一個列數的中間變量
    NSInteger tempColumn = 0;
    //設置高度小的中間變量 在這裏咱們把第0列的高度給他,這樣能夠減小循環次數,提升效率
    CGFloat minColumnHeight = [self.CXcolumnHeights[0] doubleValue];
    for (NSInteger i = 1; i < CXcolumnCount; i ++) {
        if (minColumnHeight > [self.CXcolumnHeights[i] doubleValue]) {
            minColumnHeight = [self.CXcolumnHeights[i] doubleValue];
            tempColumn = i;
        }
    }
    X = CXdefaultEdgeInsets.left + (width + CXcolumnMagin) * tempColumn;
    //獲取Y
    Y = minColumnHeight;
    if (Y != CXdefaultEdgeInsets.top) {
        Y += CXrowMagin;
    }
    //設置cell的frame
    CXattributes.frame = CGRectMake(X, Y, width, height);
    //更新高度最矮的那列的高度
    self.CXcolumnHeights[tempColumn] = @(CGRectGetMaxY(CXattributes.frame));
    
    return CXattributes;
}
//返回collegeView的Content的大小
- (CGSize)collectionViewContentSize{
    //雖然說返回的是大小,可是咱們這裏主要的是height
    CGFloat maxColumnHeight = [self.CXcolumnHeights[0] doubleValue];
    for (NSInteger i = 1; i < CXcolumnCount; i++) {

        CGFloat columnHeight = [self.CXcolumnHeights[i] doubleValue];
        
        if (maxColumnHeight < columnHeight) {
            maxColumnHeight = columnHeight;
        }
    }
    return CGSizeMake(0, maxColumnHeight + CXdefaultEdgeInsets.bottom);
    
}

@end
複製代碼

到此爲止瀑布流的實現也就結束了。

在這裏說明幾點值得注意的地方。

  • 瀑布流中的cell排布順勢是根據當前列的高度有關的(例如:若是當前第三列是最短的,可是按正常狀況下cell應該排在第一列,那麼這個時候,新的cell會排在第三列,這是爲了不某一列高度特別長或某一列的高度特別短)
  • 在實際應用中一般cell的大小是根據數據的來處理的
  • UIcollectionView的content的高度是不肯定的,所以咱們要根據內容設定高度。
  • 當涉及到刷新的時候咱們要注意cell的佈局屬性是否在新數據到來前清空了。
相關文章
相關標籤/搜索