OC-UICollectionView實現瀑布流

来源:http://www.cnblogs.com/chenjiangxiaoyu/archive/2017/07/11/7150619.html
-Advertisement-
Play Games

UICollectionView實現瀑布流 在iOS中可以實現瀑布流的目前已知的有2種方案: 本文中我們介紹第二種實現方案首先我們需要自定義一個繼承於UICollectionViewLayout的layout,然後需要重寫四個方法: 第一個方法是做一些初始化的操作,這個方法必須先調用一下父類的實現第 ...


UICollectionView實現瀑布流

在iOS中可以實現瀑布流的目前已知的有2種方案:

  1. 使用UIScrollView自己封裝一套,這種方案是應用於iOS6之前的,因為iOS6才出來UICollectionView,不過現在這種方案已經不怎麼用了,還得自己封裝。而且自己封裝的性能不一定有系統的要好。
  2. 使用系統自帶的UICollectionView,然後自定義layout,自己實現瀑布流效果

本文中我們介紹第二種實現方案
首先我們需要自定義一個繼承於UICollectionViewLayout的layout,然後需要重寫四個方法:

  1. (void)prepareLayout
  2. (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
  3. (UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath
  4. (CGSize)collectionViewContentSize

第一個方法是做一些初始化的操作,這個方法必須先調用一下父類的實現
第二個方法返回的是一個裝著UICollectionViewLayoutAttributes的數組
第三個方法返回indexPath位置的UICollectionViewLayoutAttributes
第四個方法是返回UICollectionView的可滾動範圍

如何實現瀑布流

首先我們需要明白一點瀑布流的排列,瀑布流是大小不規則的一些控制項分佈在手機屏幕上面,然後肯定有長度高的也有矮的(就像人的身高一樣,哈哈哈),當排滿第一排的時候就會往下繼續排,那麼這個應該往哪裡放呢,==答案就是把它放到第一排最短的那個下麵==,以此類推,按照這個規律排列下去。
明白了這一點我們接下來就該寫代碼了
首先我們創建兩個數組一個裝著cell的佈局屬性,另一個裝著當前cell的總高度

//c存放所有cell的佈局屬性
@property (nonatomic, strong) NSMutableArray *attrsArray;
//存放所有列的當前高度
@property (nonatomic, strong) NSMutableArray *columnHeights;
/** 內容的高度 */
@property (nonatomic, assign) CGFloat contentHeight;

  

- (void)prepareLayout
{
    [super prepareLayout];

    self.contentHeight = 0;

    //清除之前計算的所有高度,因為刷新的時候回調用這個方法
    [self.columnHeights removeAllObjects];
    for (NSInteger i = 0; i < DefaultColumnCpunt; i++) {
        [self.columnHeights addObject:@(self.edgeInsets.top)];
    }

    //把初始化的操作都放到這裡
    [self.attrsArray removeAllObjects];

    //開始創建每一個cell對應的佈局屬性
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (NSInteger i = 0; i < count; i++) {
        // 創建位置
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        // 獲取indexPath位置cell對應的佈局屬性
        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
        [self.attrsArray addObject:attrs];
    }
}

  首先把cell的高度設置為self.edgeInsets.top不然這裡會崩潰。然後取出來item的個數,然後迴圈取出每個item的UICollectionViewLayoutAttributes,然後把它加入到attsArray,然後在- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect這個方法中直接返回attrsArray即可。

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    CGFloat collectionViewW = self.collectionView.frame.size.width;

    CGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right -(self.columnCount - 1) * self.columnMargin) / self.columnCount;

    CGFloat h = [self.delegate WaterFlowLayout:self heightForRowAtIndexPath:indexPath.item itemWidth:w];

    NSInteger destColumn = 0;

    CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
    for (NSInteger i = 0; i < self.columnCount; i++) {
        CGFloat columnHeight = [self.columnHeights[i] doubleValue];

        if (minColumnHeight > columnHeight) {
            minColumnHeight = columnHeight;
            destColumn = i;
        }
    }

    CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin);
    CGFloat y = minColumnHeight;
    if (y != self.edgeInsets.top) {
        y += self.rowMargin;
    }

    attrs.frame = CGRectMake(x, y, w, h);

    self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));

    CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];
    if (self.contentHeight < columnHeight) {
        self.contentHeight = columnHeight;
    }
    return attrs;

}

  上面這個方法是計算item的位置的代碼,首先取出來indexPathUICollectionViewLayoutAttributes對象,然後取出來w,h,核心代碼如下:

NSInteger destColumn = 0;

    CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
    for (NSInteger i = 0; i < self.columnCount; i++) {
        CGFloat columnHeight = [self.columnHeights[i] doubleValue];

        if (minColumnHeight > columnHeight) {
            minColumnHeight = columnHeight;
            destColumn = i;
        }
    }

    CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin);
    CGFloat y = minColumnHeight;
    if (y != self.edgeInsets.top) {
        y += self.rowMargin;
    }

  首先弄了一個標示destColumn來做記錄是那一列的,然後定義一個minColumnHeight為最小的列的高度,取出來self.columnHeights[0]的高度,這裡預設為它就是最小的,然後進行for迴圈遍歷,取出來i位置上面的高度,如果這個值小於之前的minColumnHeight,那麼取出來的這個高度就是最小的高度了,然後把i的值賦值給destColumn,然後x的值就是上面代碼中的相加的結果,y的值就是繼續加上間距

- (CGSize)collectionViewContentSize
{
//    CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
//    
//    for (NSInteger i = 1; i < DefaultColumnCpunt; i++) {
//        // 取得第i列的高度
//        CGFloat columnHeight = [self.columnHeights[i] doubleValue];
//        
//        if (maxColumnHeight < columnHeight) {
//            maxColumnHeight = columnHeight;
//        }
//    }
    return CGSizeMake(0, self.contentHeight + self.edgeInsets.bottom);
}

  傳送門:gitHub


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 模板字元串: "use strict"; let a = ; console.log(a); 模板字元串寫在撇號(反引號)裡邊。 let a = `my name is DaPaang i am 21 years old `; console.log(a); 模板字元串支持換行書寫; let ...
  • 閑來無事寫了個小demo,想上傳到GitHub上,發現得使用git進行上傳,所以得先瞭解下git . 1、git是什麼 分散式版本控制器 2、svn與git的區別svn:是集中式的版本控制系統,版本庫是集中存放在中央伺服器的,工作時,要先從中央伺服器取得最新的版本,工作結束了,再把自己的活推送給中央 ...
  • iframe的url可以前端任何地址,這樣就可能出現漏洞,如果釣魚網站通過js把src改成了危險地址,如果沒有監控,就會有很大隱患。所以監控iframe的url變化就是必須要解決的問題了。 第一印象的解決方案是通過setInterval輪詢監控,貌似不太理想了,而且有延遲。 千般搜索,終於找到了好的 ...
  • 初次嘗試微信小程式開發,在此寫下步驟以做記錄和分享。 1.在網上找了很多資料,發現這位知乎大神提供的資料非常全面。 鏈接 https://www.zhihu.com/question/50907897#answer-46908609 2.按照步驟安裝微信開發者工具以及註冊用戶搭建環境,詳細步驟見鏈接 ...
  • 轉載請標明原文鏈接:http://www.cnblogs.com/zhanggui/p/7151795.html 前言 上一篇文章對App Extension做了簡單介紹以及對Share Extension的使用做了簡單說明,本篇文章主要是對Sticker Pack Extension進行介紹。 開 ...
  • 我們對於IOS的瞭解最多應該就是蘋果手機獨有的IOS系統吧,也可以說是單任務管理器,這可以說是一個優勢,但是隨著技術提升IOS慢慢有被超越的趨勢,但是很多大公司還是需要這方面的開發人才,那麼今天我們來談談IOS開發的入門所需要要具備的知識和技能,如果想要成為一個高薪技術人才那麼你們就要努力了。 一基 ...
  • javaMail,是提供給開發者處理電子郵件相關的編程介面。它是Sun發佈的用來處理email的API。它可以方便地執行一些常用的郵件傳輸。我們可以基於JavaMail開發出類似於Microsoft outlook的應用程式。JavaMail是可選包,因此如果需要使用的話你需要首先從java官網上下 ...
  • 1. 下載Charles Proxy 4.1.4版本,百度雲盤下載或去官網下載 2. 安裝後先打開Charles一次(Windows版可以忽略此步驟) 3. 在這個網站(http://charles.iiilab.com/)下載破解文件 charles.jar 4. 替換掉原文件夾里的charles ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...