自定義UICollectinviewFlowLayout,即實現瀑布流

来源:http://www.cnblogs.com/xueyao/archive/2016/02/13/5188321.html
-Advertisement-
Play Games

如圖所示,通過實現不規則的網格分佈,來顯示出不同的效果。因為集合視圖必須要指定佈局還可以顯示,所以自定義佈局就可以實現瀑布流的效果。 //創建佈局對象 WaterFlowLayout *flowLayout = [[WaterFlowLayout alloc] init]; flowLayout.d


如圖所示,通過實現不規則的網格分佈,來顯示出不同的效果。因為集合視圖必須要指定佈局還可以顯示,所以自定義佈局就可以實現瀑布流的效果。

//創建佈局對象
    WaterFlowLayout *flowLayout = [[WaterFlowLayout alloc] init];
    
    flowLayout.delegate = self;
    flowLayout.numberOfColumn = 3;
    
    //創建集合視圖
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];

因為系統自帶的佈局有四個方法,分別實現了item大小,分區間隔,最小行間距,item之間的間隙大小

@protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate>
@optional
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;

所以,自定義FlowLayout,並定義協議,以便定義這些方法。

@protocol WaterFlowLayoutDelegate <NSObject>

//關鍵方法,此方法的作用是返回每一個item的size大小
//數據中原始圖片大小
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
//分區間隔
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
//得到 item之間的間隙大小
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
//最小行間距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;

@end

@interface WaterFlowLayout : UICollectionViewLayout

//瀑布流一共多少列
@property (nonatomic, assign) NSUInteger numberOfColumn;

@property (nonatomic, assign) id<WaterFlowLayoutDelegate>delegate;

看圖可知,最小高的的item,將作為下一列item的起點。

@interface WaterFlowLayout ()

//存放每一列的高度
@property (nonatomic, retain) NSMutableArray *columnHeightsArray;

//存放 每一個item的 屬性 包含 frame以及下標
@property (nonatomic, retain) NSMutableArray *attributesArray;

@end

@implementation WaterFlowLayout

//獲取最小高度的方法
- (CGFloat)minHeight
{
    CGFloat min = 100000;
    for (NSNumber *height in _columnHeightsArray) {
        CGFloat h = [height floatValue];
        if (min > h) {
            min = h;
        }
    }
    return min;
}

//獲取最大值
- (CGFloat)maxHeight
{
    CGFloat max = 0;
    for (NSNumber *height in _columnHeightsArray) {
        CGFloat h = [height floatValue];
        if (max < h) {
            max = h;
        }
    }
    return max;
}

//找到最小高的下標
- (NSUInteger)indexOfMinHeight
{
    NSUInteger index = 0;
    for (int i = 0; i < [_columnHeightsArray count]; i ++) {
        CGFloat height = [_columnHeightsArray[i] floatValue];
        if (height == [self minHeight]) {
            index = i;
            return index;
        }
    }
    return index;
}

//重寫父類的佈局方法
- (void)prepareLayout
{
    [super prepareLayout];
    
    _attributesArray = [[NSMutableArray alloc] init];
    
    _columnHeightsArray = [[NSMutableArray alloc] initWithCapacity:self.numberOfColumn];
    
    //給列高數組裡面的對象賦初值
    for (int i = 0; i < self.numberOfColumn; i ++) {
        [_columnHeightsArray addObject:@0.0];
    }
    
    CGFloat totalWidth = self.collectionView.frame.size.width;
    
    //創建 每個item frame中的x、y
    CGFloat x = 0;
    CGFloat y = 0;
    
    NSUInteger itemCount = [self.collectionView numberOfItemsInSection:0];
    
    for (int i = 0; i < itemCount; i ++) {
        //得到集合視圖中 列間隙的個數
        NSUInteger numberOfSpace = self.numberOfColumn - 1;
        
        //代理對象執行代理方法,得到 item之間的間隙大小
        CGFloat spaceWidth = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:0];
        
        //求每列的寬度,也就是每個item的width
        CGFloat width = (totalWidth - spaceWidth * numberOfSpace) / self.numberOfColumn;
        
        
        //獲取每一個itemSize的大小
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        
        //數據中原始圖片大小
        CGSize imageSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
    
        //通過 約分公式得到固定寬之後的高度是多少
        CGFloat height = width * imageSize.height / imageSize.width;
        
        
        UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        
        //記錄每一個item的大小和位置
        attribute.frame = CGRectMake(x, y, width, height);
        
        //數組保存每個item的位置信息
        [_attributesArray addObject:attribute];
        
        NSLog(@"item = %d",i);
        NSLog(@"x = %.2f y = %.2f width = %.2f height = %.2f",x,y,width,height);
        
        //求列高最小的那一列的下標
        NSUInteger minHeightIndex = [self indexOfMinHeight];
        
        //求出最小列的高度
        CGFloat minHeight = [_columnHeightsArray[minHeightIndex] floatValue];
        
        //求出行高
        CGFloat lineHeight = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:0];
        
        //上一次總的列高 加上 行高 加上新加上的item的height,才是現在這一列的總高度
        //minHeight為最小列現在的高度
        //lineHeight為行間距
        //height為新加的item的高
        _columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height];
        
        //重新算最小列高的下標
        minHeightIndex = [self indexOfMinHeight];
        
        //算下一次新加的item的x和y值
        x = (spaceWidth + width) * minHeightIndex;
        
        y = [self minHeight];
    }
}

//重寫這個方法,可以返回集合視圖的總高度
- (CGSize)collectionViewContentSize
{
    return CGSizeMake(self.collectionView.frame.size.width, [self maxHeight]);
}


- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return _attributesArray;
}

註意,最後一個方法的實現,即- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect,如果這個方法不寫,集合視圖是顯示不出來的,這個方法是次保存的每個item的信息重新告訴集合視圖,進行顯示。


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

-Advertisement-
Play Games
更多相關文章
  • 出場: 首先我們來說說為什麼需要label標簽,雖然我們已經知道有break,continue跳出迴圈,但如果是多重迴圈那麼它們就顯的無能為力了,所以就出現了label這個標簽來為我們服務。 我們先來看看單獨使用break的情況 1 for(var i=0;i<4;i++){ 2 for(var j
  • [在此處輸入文章標題] // JScript 文件 /* ================================================================== JS 公共函數 080827 =======================================
  • 1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>無標題文檔</title> 6 <style> 7 .fontSize22 8 { 9 font-size:22px; 10 } 11 .fontWeight
  • ajax在用於非同步交互以來,一直被廣泛使用,其使用語法格式基本如下: 基本格式為$.ajxa({ type:"",數據傳送類型POST,GET url:"",處理地址 data:"",傳送數據, dataType:"",返回數據類型, success:function(){},成功並接收返回值, e
  • 作者: "@gzdaijie" 本文為作者原創,轉載請註明出處:http://www.cnblogs.com/gzdaijie/p/5187171.html 。 1.寫在前面 之前使用過有道雲筆記和為知筆記,後來偶然喜歡上用Markdown寫文檔。被Markdown的簡潔與大氣所折服,因此拋棄了有道
  • 一、問題描述 基於百度地圖實現檢索指定城市指定公交的交通路線圖,效果如圖所示 二、通用組件Application類,主要創建並初始化BMapManager public class App extends Application { static App mDemoApp; //百度MapAPI的管
  • 前言:本篇隨筆介紹的是XML解析。 正文: 1、XML解析方式有2兩種: DOM:一次性將整個XML數據載入進記憶體進行解析,比較適合解析小文件 SAX:從根元素開始,按順序一個元素一個元素往下解析,比較適合解析大文件 2、IOS中XML解析方案有很多種: 2-1、第三方框架: libxml2:純C語
  • Android Studio apk 打包流程(轉)http://blog.chinaunix.net/uid-26000296-id-5567890.html
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...