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

來源:互聯網
上載者:User

標籤:

       我在前面多篇部落格中詳細講解了CollectionView的使用與自訂CollectionViewCell的設計,可以參考《iOS開發實戰——CollectionView點擊事件與鍵盤隱藏結合案例》《iOS進階開發——CollectionView修改cell的文本及模型重構》這幾篇部落格。但是今天還是需要來講講CollectionView實現中的一個小小的坑,這是我最近在網上瀏覽時發現很多開發人員經常犯的錯,所以我覺得有必要來好好談一談。

       一個CollectionView控制項中,兩個cell之間的間距如何設定?這是一個很常見的問題。當我們在網上搜這個問題的時候,很多人告訴你使用UICollectionViewDelegateFlowLayout這個代理中的minimumInteritemSpacingForSectionAtIndex方法來設定。其實這完全錯了,當你真的用這個方法去設定間距的時候,發現怎麼都設定不成自己的需求,真的是大相徑庭。本篇部落格就要來解決這個問題,範例程式碼上傳至 https://github.com/chenyufeng1991/SpaceOfCollectionView 。

(1)首先自訂一個CollectionViewCell,繼承自UICollectionViewCell。在這個cell中放一張圖片填充,該檔案定義為CustomCollectionViewCell.

CustomCollectionViewCell.h檔案如下:

#import <UIKit/UIKit.h>#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)#define CELL_WIDTH01 (SCREEN_WIDTH - 80) / 3#define CELL_WIDTH02 70@interface CustomCollectionViewCell : UICollectionViewCell@property (nonatomic, strong) UIImageView *imageView;@end

CustomCollectionViewCell.m檔案如下:

#import "CustomCollectionViewCell.h"#import "Masonry.h"@implementation CustomCollectionViewCell- (instancetype)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self)    {        self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, CELL_WIDTH02, CELL_WIDTH02)];        [self addSubview:self.imageView];        // 圖片填充滿整個cell        [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {            make.edges.equalTo(self);        }];    }    return self;}@end

上面的宏定義SCREEN_WIDTH表示螢幕寬度。CELL_WIDTH01和CELL_WIDTH02可以用來設定cell的寬高。


(2)我的主檔案為MainViewController.m,首先需要聲明三個代理:

UICollectionViewDelegate,

UICollectionViewDataSource,

UICollectionViewDelegateFlowLayout


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

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

(4)宏定義幾個變數:

#define ARRAY_COUNT 10#define MINIMUM_ITEM_SPACE 5#define MINIMUM_LINE_SPACE 5

ARRAY_COUNT是cell的數量;

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

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


(5)UI布局

- (void)configUI{    // CollectionView    self.collArr = [[NSMutableArray alloc] init];    for (int i = 0; i < ARRAY_COUNT; i++)    {        [self.collArr addObject:[UIImage imageNamed:@"beauty"]];    }    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];    [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];// CollectionView的滾動方向,只能二選一    // 初始化,可以不設定寬高,通過下面的mas_makeConstraints自動布局完成。    self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 100, SCREEN_WIDTH, CELL_WIDTH02 * 2) collectionViewLayout:flowLayout];    self.collectionView.bounces = NO;    [self.collectionView registerClass:[CustomCollectionViewCell class] forCellWithReuseIdentifier:@"CollectionCell"];    self.collectionView.delegate = self;    self.collectionView.dataSource = self;    [self.view addSubview:self.collectionView];    [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {        make.top.equalTo(self.view).offset(64);        make.left.equalTo(self.view);        make.right.equalTo(self.view);        make.height.equalTo(@(CELL_WIDTH02 * 2));    }];}

cell的數量可以通過宏定義ARRAY_COUNT來設定。

這裡的Autolayout我使用Masonry進行自動布局,關於Masonry的使用可以參考《Autolayout第三方庫Masonry的入門與實踐》。

這裡我設定UICollection的寬度為螢幕寬度,高度為2 * CELL_WIDTH02.

UICollectionViewFlowLayout是設定CollectionView內部cell的布局,必須進行設定。


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

#pragma mark - UiCollectionViewDataSource- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{    return self.collArr.count;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{    CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionCell" forIndexPath:indexPath]; // 重用cell    if (cell == nil)    {        // 當重用cell為空白時,建立新的cell        cell = [[CustomCollectionViewCell alloc] init];    }    cell.imageView.image = self.collArr[indexPath.row];    return cell;}

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

cellForItemAtIndexPath是為cell進行賦值。


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

#pragma mark - UICollectionViewDelegateFlowLayout// 該方法是設定cell的size- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{    return CGSizeMake(CELL_WIDTH02, CELL_WIDTH02);}// 該方法是設定一個section的上左下右邊距- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{    // 注意,這裡預設會在top有+64的邊距,因為狀態列+導覽列是64.    // 因為我們常常把[[UIScreen mainScreen] bounds]作為CollectionView的地區,所以蘋果API就預設給了+64的EdgeInsets,這裡其實是一個坑,一定要注意。    // 這裡我暫時不用這個邊距,所以top減去64    // 所以這是就要考慮你是把Collection從螢幕左上方(0,0)開始放還是(0,64)開始放。    return UIEdgeInsetsMake(-64, 0, 0, 0);}// 兩個cell之間的最小間距,是由API自動計算的,只有當間距小於該值時,cell會進行換行- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{    return MINIMUM_ITEM_SPACE;}// 兩行之間的最小間距- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{    return MINIMUM_LINE_SPACE;}


-- 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效果如下:

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


可以看到一行的cell只有3個了。因為當一行cell=4的時候,間距13.33小於了我設定的最小間距14,所以系統不得不一行減少一個cell來滿足這個最小間距的要求。現在計算一下間距:(320 - 3 * 70) /2 = 55 > 14最小間距,滿足條件, 通過來進行驗證:


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


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

       

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.