IOS 瀑布流UICollectionView實現

来源:http://www.cnblogs.com/xubaoaichiyu/archive/2016/04/09/5371615.html
-Advertisement-
Play Games

IOS 瀑布流UICollectionView實現 在實現瀑布流之前先來看看瀑布流的雛形(此方法的雛形 UICollectionView) 對於UICollectionView我們有幾點註意事項 它和tableView不一樣,ContentView的內容完全需要我們自己去添加。 它與tablevie ...


IOS 瀑布流UICollectionView實現


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

對於UICollectionView我們有幾點註意事項

  • 它和tableView不一樣,ContentView的內容完全需要我們自己去添加。
  • 它與tableview相比,他的初始化需要FlowLayout並且大部分操作在其上。
  • UIcollectionView的實用性極強,雖然有時他並不是最好的解決方案,但是它可以很靈活的實現各種效果。

圖(一)

如圖,模擬器上展示的是很多方格,但是值得註意的是他們是有規則的。

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

我們所說的要實現瀑布流就是要實現它的不整潔,但是規律(這裡我說的是規律)

正題

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

為了實現瀑布流我們所要實現的便是改變他的格局部署。

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

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

實現效果

代碼

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

我在註釋中簡單介紹。

---

//
//  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的佈局屬性是否在新數據到來前清空了。

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

-Advertisement-
Play Games
更多相關文章
  • 一般的手機沒有root許可權,進不去data/data目錄,當手機刷機了後,擁有root許可權,就可以進入data/data目錄,查看我們保存的密碼文件,因此我們需要對存入的密碼進行MD5加密 獲取MessageDigest信息摘要器對象,調用MessageDigest.getInstance(“md5 ...
  • 一直以來,我們把所有的段描述符都放在GDT中,而不管它屬於內核還是用戶程式,為了有效地在任務之間實施隔離,處理器建議每個任務都應當具有自己的描述符表,稱為局部描述符表LDT,並且把專屬於自己的那些段放到LDT中。 和GDT一樣,LDT也是用來存放描述符的。不同之處在於,LDT只屬於某個任務。或者說, ...
  • 原博客地址:http://www.cnblogs.com/tianzhijiexian/p/4161811.html 相信看這篇文章的人都應該知道android中的Dialog了吧,如果對於Dialog還不是很瞭解可以看我之前的一篇詳解文章: Dialog詳解:http://www.cnblogs. ...
  • 跳轉到指定app的實現 IOS中應用的跳轉是通過URL實現的,因此在實現應用跳轉之前我們要設置一下對應的URL。 圖一(尋找配置軟體的URL) 圖二(具體配置選項) 註意: 如果IOS版本為IOS9 我們需要為app設置白名單。 實現跳轉的前提是有這個app,因此我們需要把被跳轉的app先運行,即安 ...
  • Mask屬性介紹 Mask平時用的最多的是masksToBounds 吧. 其實除此以外Mask使用場景很多,看完之後你會發現好真是好用的不要不要的... 先來瞭解下Mask屬性到底是什麼? Mask 英文解釋是蒙板/面罩,平時我們稱為蒙層. 在蘋果官方文檔里如下圖,意思是Mask是一個可選的Lay ...
  • 今天我們介紹的是Checkbox多選框: 1.Activity 2.xml文件如下: 3.效果圖如下: ...
  • 在移動應用滿天飛的時代,隨著移動支付的盛行,很多應用中都集成了支付功能。之前的支付一直不是我負責,近期這個項目我負責訂單模塊少不了要做支付,每每提起支付就覺得怕怕,覺得很難,但當真正做的時候卻遠遠沒有想象中的那麼難。支付寶的SDK提供了demo,我們只需要配置好一些基本信息,這個demo就可以正常支 ...
  • 今天我們的主要內容就是安卓的主要幾個基礎的佈局方式。(主要佈局如下:) 1.線性佈局(LinerLayout) 2.相對佈局(RelativeLayout) 3.表格佈局(TableLayout) 4.網格佈局(GridLayout) 5.絕對佈局(AbsoluteLayout) 6.幀佈局(Fra ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...