iOS 瀑布流基本實現(xiàn)

一颤难、瀑布流設計方案

不可取.png
過于復雜.png
最優(yōu)方案.png

二、瀑布流設計思路分析

  • 1已维、自定義流水布局中行嗤,指定滾動方向、默認列數(shù)垛耳、行間距栅屏、列間距、以及指定cell的大小itemSize
  • 2堂鲜、可以提供一個數(shù)組columnMaxYs(記錄當前每一列的最大Y值)栈雳,假如3列,我們就提供一個3個元素的數(shù)組缔莲,記錄所有布局屬性
      1. columnMaxYs實現(xiàn)懶加載甫恩,
    • 2.并在prepareLayout方法中 :
      • 1.先將columnMaxYs清空。
      • 2.再進行初始化每個元素為0.
      • 3.獲取所有的Cell的布局屬性酌予,而每一個Cell的布局屬性通過調(diào)用layoutAttributesForItemAtIndexPath:方式獲取磺箕,而調(diào)用該方法奖慌,就會執(zhí)行第4步

(至于為什么在prepareLayout方法中初始化,而不是在init方法初始化:
是因為松靡,該方法每次刷新都會調(diào)用简僧,而init方法中只會在創(chuàng)建布局對象的時候只執(zhí)行一次,
例如:如果進行下拉刷新最新數(shù)據(jù)的時候雕欺,需求重新初始化數(shù)據(jù)岛马,而如果我們使用的是init方法的話,并不會調(diào)用也就并不會清除之前的然后初始化屠列,
而使用該方法prepareLayout可以辦到啦逆,因為它會再次調(diào)用,而init不會調(diào)用)
```
+ 3.獲取所有Cell的布局屬性笛洛,
注意:對與所有Cell的布局屬性夏志,在第一次加載的時候需要計算一次,而當刷新collectionView的時候苛让,當然也需要重新計算:所以我們提供一個布局屬性的數(shù)組沟蔑,來保存所有Cell的布局刷新,避免不必要的計算狱杰。
——> 放在哪瘦材? 計算最好呢?
———> 首選放在prepareLayout方法中仿畸,因為它會調(diào)用一次加載食棕,而且當刷新的時候也會調(diào)用,滿足需求错沽,我們先將之前的全部移除宣蠕,然后重新返回最新的布局屬性數(shù)組; 但是甥捺,最好不要放在layoutAttributesForElementsInRect:方法(返回所有元素的布局屬性數(shù)組中)抢蚀,因為改方法在滾動collectionView的時候,會頻繁的調(diào)用镰禾,比較銷毀性能皿曲。

  • 3、在layoutAttributesForElementsInRect:方法(返回所有元素的布局屬性數(shù)組 )

    • 返回之前保存的所有Cell的布局屬性數(shù)組
  • 4吴侦、我們可以在layoutAttributesForItemAtIndexPath: 方法: 來調(diào)整 Cell的布局屬性 屋休, 指定Cell的 frame

 1.在該方法中拿到當前cell的默認布局屬性attrs,進行下面的調(diào)整备韧,就可以實現(xiàn)瀑布流了
  2.遍歷columnMaxYs數(shù)組劫樟,需要找出最短一列的 列號 與 最大Y值
  3. 確定當前Cell的 存放的x.y位置 以及widht與height
         —> width:根據(jù)屏幕寬度與列數(shù)以及每列的寬度求出.  height:服務器返回的
         —> x:需要根據(jù)當前最短一列的列號與Cell的寬度與間距可以求出來;y : 可以根據(jù)當前最短一列的最大Y值 + 行間距可以求出
 4.重新設置修改當前Cell的布局屬性attrs 的 frame即可〉蓿—> 之前已經(jīng)拿到當前Cell的 默認布局屬性奶陈,以及上一步已經(jīng)獲取到當前Cell需要存放的x.y位置后,
  5.將修改Cell布局屬性之后的附较,當前列當前Cell的Y值最大吃粒,所有我們要將該值記錄到數(shù)組columnMaxYs中,以便下次對比
      ```

5拒课、注意:我們需要設置collectionView的contentSize徐勃,它才會滾動,那么我們?nèi)绾卧O置呢早像?

——> 在定義布局類中僻肖,系統(tǒng)提供了一個collectionViewContentSize的get對象方法(決定collectionView的contentSize)
—> contentSize的高度為:計算出最長那一列的最大Y值,也就是columnMaxYs的最大值 + 行間距
```

三卢鹦、瀑布流的基本實現(xiàn)

效果圖.png
  • 1.創(chuàng)建一個控制器JPCollectionViewController臀脏,繼承UICollectionViewController,使用我們自定義的流水布局JPWaterflowLayout(實現(xiàn)見其后)
#import "JPCollectionViewController.h"
#import "JPWaterflowLayout.h" // 自定義流水布局

@interface JPCollectionViewController ()

@end

@implementation JPCollectionViewController

static NSString * const reuseIdentifier = @"cellID";

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 切換布局
    self.collectionView.collectionViewLayout = [[JPWaterflowLayout alloc] init];
}

#pragma mark <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 30;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
    cell.backgroundColor = [UIColor orangeColor];
    return cell;
}
@end
  • 2.自定義流水布局JPWaterflowLayout法挨,繼承UICollectionViewLayout
#import "JPWaterflowLayout.h"

#define JPCollectionW self.collectionView.frame.size.width

/** 每一行之間的間距 */
static const CGFloat JPDefaultRowMargin = 10;
/** 每一列之間的間距 */
static const CGFloat JPDefaultColumnMargin = 10;
/** 每一列之間的間距 top, left, bottom, right */
static const UIEdgeInsets JPDefaultInsets = {10, 10, 10, 10};
/** 默認的列數(shù) */
static const int JPDefaultColumsCount = 3;

@interface JPWaterflowLayout()
/** 每一列的最大Y值 */
@property (nonatomic, strong) NSMutableArray *columnMaxYs;
/** 存放所有cell的布局屬性 */
@property (nonatomic, strong) NSMutableArray *attrsArray;
@end

@implementation JPWaterflowLayout

#pragma mark - 懶加載
- (NSMutableArray *)columnMaxYs
{
    if (!_columnMaxYs) {
        _columnMaxYs = [[NSMutableArray alloc] init];
    }
    return _columnMaxYs;
}

- (NSMutableArray *)attrsArray
{
    if (!_attrsArray) {
        _attrsArray = [[NSMutableArray alloc] init];
    }
    return _attrsArray;
}

#pragma mark - 實現(xiàn)內(nèi)部的方法
/**
 * 決定了collectionView的contentSize
 */
- (CGSize)collectionViewContentSize
{
    // 找出最長那一列的最大Y值
    CGFloat destMaxY = [self.columnMaxYs[0] doubleValue];
    for (NSUInteger i = 1; i<self.columnMaxYs.count; i++) {
        // 取出第i列的最大Y值
        CGFloat columnMaxY = [self.columnMaxYs[i] doubleValue];
        
        // 找出數(shù)組中的最大值
        if (destMaxY < columnMaxY) {
            destMaxY = columnMaxY;
        }
    }
    return CGSizeMake(0, destMaxY + JPDefaultInsets.bottom);
}

- (void)prepareLayout
{
    [super prepareLayout];
    
    // 重置每一列的最大Y值
    [self.columnMaxYs removeAllObjects];
    for (NSUInteger i = 0; i<JPDefaultColumsCount; i++) {
        [self.columnMaxYs addObject:@(JPDefaultInsets.top)];
    }
    
    // 計算所有cell的布局屬性
    [self.attrsArray removeAllObjects];
    NSUInteger count = [self.collectionView numberOfItemsInSection:0];
    for (NSUInteger i = 0; i < count; ++i) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
        [self.attrsArray addObject:attrs];
    }
}

/**
 * 說明所有元素(比如cell谁榜、補充控件幅聘、裝飾控件)的布局屬性
 */
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return self.attrsArray;
}

/**
 * 說明cell的布局屬性
 */
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    /** 計算indexPath位置cell的布局屬性 */
    
    // 水平方向上的總間距
    CGFloat xMargin = JPDefaultInsets.left + JPDefaultInsets.right + (JPDefaultColumsCount - 1) * JPDefaultColumnMargin;
    // cell的寬度
    CGFloat w = (JPCollectionW - xMargin) / JPDefaultColumsCount;
    // cell的高度凡纳,測試數(shù)據(jù),隨機數(shù)
    CGFloat h = 50 + arc4random_uniform(150);

    // 找出最短那一列的 列號 和 最大Y值
    CGFloat destMaxY = [self.columnMaxYs[0] doubleValue];
    NSUInteger destColumn = 0;
    for (NSUInteger i = 1; i<self.columnMaxYs.count; i++) {
        // 取出第i列的最大Y值
        CGFloat columnMaxY = [self.columnMaxYs[i] doubleValue];
        
        // 找出數(shù)組中的最小值
        if (destMaxY > columnMaxY) {
            destMaxY = columnMaxY;
            destColumn = i;
        }
    }
    
    // cell的x值
    CGFloat x = JPDefaultInsets.left + destColumn * (w + JPDefaultColumnMargin);
    // cell的y值
    CGFloat y = destMaxY + JPDefaultRowMargin;
    // cell的frame
    attrs.frame = CGRectMake(x, y, w, h);
    
    // 更新數(shù)組中的最大Y值
    self.columnMaxYs[destColumn] = @(CGRectGetMaxY(attrs.frame));
    
    return attrs;
}
@end
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帝蒿,一起剝皮案震驚了整個濱河市荐糜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌葛超,老刑警劉巖暴氏,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绣张,居然都是意外死亡答渔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門侥涵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沼撕,“玉大人,你說我怎么就攤上這事芜飘∥癫颍” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵嗦明,是天一觀的道長笼沥。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么奔浅? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任馆纳,我火速辦了婚禮,結果婚禮上乘凸,老公的妹妹穿的比我還像新娘厕诡。我一直安慰自己,他們只是感情好营勤,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布灵嫌。 她就那樣靜靜地躺著,像睡著了一般葛作。 火紅的嫁衣襯著肌膚如雪寿羞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天赂蠢,我揣著相機與錄音绪穆,去河邊找鬼。 笑死虱岂,一個胖子當著我的面吹牛玖院,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播第岖,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼难菌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蔑滓?” 一聲冷哼從身側(cè)響起郊酒,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎键袱,沒想到半個月后燎窘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蹄咖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年褐健,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澜汤。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚜迅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出银亲,到底是詐尸還是另有隱情慢叨,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布务蝠,位于F島的核電站拍谐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轩拨,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一践瓷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亡蓉,春花似錦晕翠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爸邢,卻和暖如春樊卓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杠河。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工碌尔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人券敌。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓唾戚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親待诅。 傳聞我的和親對象是個殘疾皇子叹坦,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容