iOS開發實戰——CollectionView中cell的間距設置

我在前面多篇博客中詳細講解了CollectionView的使用與自定義CollectionViewCell的設計,能夠參考《iOS開發實戰——CollectionView點擊事件與鍵盤隱藏結合案例》《iOS高級開發——CollectionView修改cell的文本及模型重構》這幾篇博客。可是今天仍是須要來說講CollectionView實現中的一個小小的坑,這是我最近在網上瀏覽時發現不少開發者常常犯的錯,因此我以爲有必要來好好談一談。git

       一個CollectionView控件中,兩個cell之間的間距如何設置?這是一個很常見的問題。當咱們在網上搜這個問題的時候,不少人告訴你使用UICollectionViewDelegateFlowLayout這個代理中的minimumInteritemSpacingForSectionAtIndex方法來設置。其實這徹底錯了,當你真的用這個方法去設置間距的時候,發現怎麼都設置不成本身的需求,真的是截然不同。本篇博客就要來解決這個問題,示例代碼上傳至 https://github.com/chenyufeng1991/SpaceOfCollectionView 。github

(1)首先自定義一個CollectionViewCell,繼承自UICollectionViewCell。在這個cell中放一張圖片填充,該文件定義爲CustomCollectionViewCell.數組

CustomCollectionViewCell.h文件以下:佈局

  1. #import <UIKit/UIKit.h>  
  2.   
  3. #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)  
  4.   
  5. #define CELL_WIDTH01 (SCREEN_WIDTH - 80) / 3  
  6. #define CELL_WIDTH02 70  
  7.   
  8. @interface CustomCollectionViewCell : UICollectionViewCell  
  9.   
  10. @property (nonatomic, strong) UIImageView *imageView;  
  11.   
  12. @end  


CustomCollectionViewCell.m文件以下:測試

  1. #import "CustomCollectionViewCell.h"  
  2. #import "Masonry.h"  
  3.   
  4. @implementation CustomCollectionViewCell  
  5.   
  6. - (instancetype)initWithFrame:(CGRect)frame  
  7. {  
  8.     self = [super initWithFrame:frame];  
  9.     if (self)  
  10.     {  
  11.         self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, CELL_WIDTH02, CELL_WIDTH02)];  
  12.         [self addSubview:self.imageView];  
  13.         // 圖片填充滿整個cell  
  14.         [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {  
  15.             make.edges.equalTo(self);  
  16.         }];  
  17.     }  
  18.     return self;  
  19. }  
  20.   
  21. @end  


上面的宏定義SCREEN_WIDTH表示屏幕寬度。CELL_WIDTH01和CELL_WIDTH02能夠用來設置cell的寬高。atom

(2)個人主文件爲MainViewController.m,首先須要聲明三個代理:.net

UICollectionViewDelegate,設計

UICollectionViewDataSource,代理

UICollectionViewDelegateFlowLayoutblog

 

(3)MainViewController.m中聲明兩個屬性:

  1. @property (nonatomic, strong) UICollectionView *collectionView;  
  2. @property (nonatomic, strong) NSMutableArray *collArr;  


(4)宏定義幾個變量:

  1. #define ARRAY_COUNT 10  
  2. #define MINIMUM_ITEM_SPACE 5  
  3. #define MINIMUM_LINE_SPACE 5  


ARRAY_COUNT是cell的數量;

 

MINIMUM_ITEM_SPACE是設置cell之間的最小間距(等下我解釋這個概念)

MINIMUM_LINE_SPACE是設置每行之間的間距。

 

(5)UI佈局

  1. - (void)configUI  
  2. {  
  3.     // CollectionView  
  4.     self.collArr = [[NSMutableArray alloc] init];  
  5.     for (int i = 0; i < ARRAY_COUNT; i++)  
  6.     {  
  7.         [self.collArr addObject:[UIImage imageNamed:@"beauty"]];  
  8.     }  
  9.   
  10.     UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];  
  11.     [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];// CollectionView的滾動方向,只能二選一  
  12.   
  13.     // 初始化,能夠不設置寬高,經過下面的mas_makeConstraints自動佈局完成。  
  14.     self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 100, SCREEN_WIDTH, CELL_WIDTH02 * 2) collectionViewLayout:flowLayout];  
  15.     self.collectionView.bounces = NO;  
  16.     [self.collectionView registerClass:[CustomCollectionViewCell class] forCellWithReuseIdentifier:@"CollectionCell"];  
  17.     self.collectionView.delegate = self;  
  18.     self.collectionView.dataSource = self;  
  19.     [self.view addSubview:self.collectionView];  
  20.     [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {  
  21.         make.top.equalTo(self.view).offset(64);  
  22.         make.left.equalTo(self.view);  
  23.         make.right.equalTo(self.view);  
  24.         make.height.equalTo(@(CELL_WIDTH02 * 2));  
  25.     }];  
  26. }  


cell的數量能夠經過宏定義ARRAY_COUNT來設置。

 

這裏的Autolayout我使用Masonry進行自動佈局,關於Masonry的使用能夠參考《Autolayout第三方庫Masonry的入門與實踐》。

這裏我設置UICollection的寬度爲屏幕寬度,高度爲2 * CELL_WIDTH02.

UICollectionViewFlowLayout是設置CollectionView內部cell的佈局,必須進行設置。

 

(6)UICollectionViewDataSource代理中方法重寫:

  1. #pragma mark - UiCollectionViewDataSource  
  2. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section  
  3. {  
  4.     return self.collArr.count;  
  5. }  
  6.   
  7. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath  
  8. {  
  9.     CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionCell" forIndexPath:indexPath]; // 重用cell  
  10.     if (cell == nil)  
  11.     {  
  12.         // 當重用cell爲空時,建立新的cell  
  13.         cell = [[CustomCollectionViewCell alloc] init];  
  14.     }  
  15.     cell.imageView.image = self.collArr[indexPath.row];  
  16.   
  17.     return cell;  
  18. }  


numberOfItemsInSection是設置section中cell的數量,返回數組數量便可,在這裏其實就是ARRAY_COUNT宏定義。

 

cellForItemAtIndexPath是爲cell進行賦值。

 

(7)UICollectionViewDelegateFlowLayout代理中方法的重寫:

  1. #pragma mark - UICollectionViewDelegateFlowLayout  
  2.   
  3. // 該方法是設置cell的size  
  4. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath  
  5. {  
  6.     return CGSizeMake(CELL_WIDTH02, CELL_WIDTH02);  
  7. }  
  8.   
  9. // 該方法是設置一個section的上左下右邊距  
  10. - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section  
  11. {  
  12.     // 注意,這裏默認會在top 有+64的邊距,由於狀態欄+導航欄是64.  
  13.     // 由於咱們經常把[[UIScreen mainScreen] bounds]做爲CollectionView的區域,因此蘋果API就默認給了+64的EdgeInsets,這裏實際上是一個坑,必定要注意。  
  14.     // 這裏我暫時不用這個邊距,因此top減去64  
  15.     // 因此這是就要考慮你是把Collection從屏幕左上角(0,0)開始放仍是(0,64)開始放。  
  16.     return UIEdgeInsetsMake(-64, 0, 0, 0);  
  17. }  
  18.   
  19. // 兩個cell之間的最小間距,是由API自動計算的,只有當間距小於該值時,cell會進行換行  
  20. - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section  
  21. {  
  22.     return MINIMUM_ITEM_SPACE;  
  23. }  
  24.   
  25. // 兩行之間的最小間距  
  26. - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section  
  27. {  
  28.     return MINIMUM_LINE_SPACE;  
  29. }  


 

 

-- sizeForItemAtIndexPath方法是設置cell的寬高,這裏我設置成CELL_WIDTH02;

-- insetForSectionAtIndex方法是設置一個section在CollectionView中的內邊距;

-- minimumInteritemSpacingForSectionAtIndex方法是設置cell之間的最小邊距(我下面會詳細講解這個方法);

-- minimumLineSpacingForSectionAtIndex方法是設置每行之間的距離;

 

(8)完成以上代碼後 ,實現的效果以下:

。---------------------------------------------------------------------------------------------------------(打個分割線,其實以上都是鋪墊,下面正式講如何設置cell之間的邊距)

     其實準確的說,cell之間的間距不是咱們手動設置的,也沒有辦法手動設置,是由系統爲咱們計算的。計算方式以下:

CollectionView寬度:CollectionWidth,

一個Cell寬度:CellWidth,

一行cell的個數:N,

cell的間距:SpaceX,

cell的最小間距:MinimumX

 

      公式以下:SpaceX = CollectionWidth - CellWidth * N(N爲正整數); 當 SpaceX >= MinimumX時,N會遞增,也就是說一行的cell數量會增多。系統會進行檢測,當增長一個cell時,SpaceX < MinimumX時(實際間距絕對不能小於這個最小間距),cell就會進行換行,因此N會取容許範圍內的最大值。因而可知,對於某一個固定的CollectionView,cell的間距只是由cell的寬度決定的。

      在我上面的例子中,是在5s模擬器下測試的,屏幕寬度爲320,cell寬度爲70,minimumInteritemSpacingForSectionAtIndex方法設置的最小cell間距爲5,因此一行只能放下4個cell,而且cell之間的間距=(320-70*4)/3 = 13.33 > 5  .而且不能放5個,由於 5 * 70 > 320了。固然cell也不可能爲3個,由於能夠設置的最大值爲4個。我這裏經過截圖來驗證這個是否正確:

經過截圖驗證,咱們的計算是正確的,由於是兩倍像素:因此2*13 = 26.

      好,爲了再次說明個人說法的正確性,minimumInteritemSpacingForSectionAtIndex方法的返回值能夠爲13如下的任何正整數,最後運行的UI都是同樣的。由於當cell=4的時候,系統計算的13.33始終大於minimumInteritemSpacingForSectionAtIndex返回值。

      如今修改代碼,minimumInteritemSpacingForSectionAtIndex返回值爲14,從新運行程序,UI效果以下:

  1. // 兩個cell之間的最小間距,是由API自動計算的,只有當間距小於該值時,cell會進行換行  
  2. - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section  
  3. {  
  4.     return 14.0f;  
  5. }  


 

能夠看到一行的cell只有3個了。由於當一行cell=4的時候,間距13.33小於了我設置的最小間距14,因此係統不得不一行減小一個cell來知足這個最小間距的要求。如今計算一下間距:(320 - 3 * 70) /2 = 55 > 14最小間距,知足條件, 經過截圖來進行驗證:

實際證實計算仍舊是正確的。

 

      如今你們應該明白了minimumInteritemSpacingForSectionAtIndex這個方法的含義了吧,也知道了如何去調整cell的間距。因此綜上所述一下,對於控制CollectionView中一行顯示的cell數量和cell間距,只能經過cell的寬高和minimumInteritemSpacingForSectionAtIndex設置最小間距來完成,而不是經過代碼手動設置的,計算任務就交給系統吧。

相關文章
相關標籤/搜索