UICollectionView的佈局是能夠本身定義的,在這篇博客中先在上篇博客的基礎上進行擴充,咱們先使用UICollectionViewFlowLayout,而後好好的介紹一下UICollectionView的一些回調方法,主要包括UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,UICollectionViewDelegate相關回調方法,並經過實例來介紹每一個回調的用法。而且給每一個Section添加定製的Header和Footer,好廢話少說進入今天的正題。git
1、Demo總覽github
下圖是本篇博客中Demo的最終運行效果,下面是咱們要作的事情:bash
一、在UICollectionViewDataSource回調方法中有一個返回Section數量的方法,以下所示,該方法和UITableView中的用法一致。在這兒咱們返回5個Section,以下所示:函數
1 #pragma mark <UICollectionViewDataSource>
2
3 /**
4 * 返回Section的個數
5 */
6 - (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
7 return 5;
8 }
複製代碼
二、在UICollectionViewDataSource的回調方法中,還有一個是返回每一個Section中Cell的數量的方法,在這咱們返回30個Cell, 以下代碼所示:佈局
1 /**
2 * 返回每一個Section中Cell的個數
3 */
4 - (NSInteger)collectionView: (UICollectionView *)collectionView
5 numberOfItemsInSection: (NSInteger)section {
6
7 return 30;
8 }
複製代碼
三、在UICollectionViewDataSource還有一個必須實現的方法, 就是選擇咱們CollectionView中所使用的Cell, 在這裏咱們所使用的Cell是在Storyboard上實現的,因此不須要在咱們的代碼中註冊Cell, 之間使用重用標示符就能夠獲取Cell的對象,以下所示:post
1 /**
2 * 返回Cell種類
3 */
4 - (UICollectionViewCell *)collectionView: (UICollectionView *)collectionView
5 cellForItemAtIndexPath: (NSIndexPath *)indexPath {
6
7 //經過Cell重用標示符來獲取Cell
8 CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: reuseIdentifier
9 forIndexPath: indexPath];
10
11 return cell;
12 }
複製代碼
四、在UICollectionViewDataSource方法中有一個可選的方法就是爲咱們的Section添加Supplementary View(追加視圖),下面是添Supplementary View(追加視圖)的步驟。在UICollectionView中的Section中咱們能夠爲其增長Header View和Footer View, 也就是官方文檔上提到的Supplementary View(追加視圖)。追加視圖是能夠重用的,也就是UICollectionReusableView。咱們能夠建立兩個UICollectionReusableView的子類,一個是Header View, 另外一個是Footer View。ui
(1)建立UICollectionReusableViewspa
追加視圖能夠在Storyboard上添加,而後設置重用標示符,在代碼中使用便可。這裏咱們是從xib文件來加載的Supplementary View, 先建立兩個UICollectionReusableView子類,在建立該子類的同時建立相應的xib文件,以下所示:代理
建立Header View和Footer View的UICollectionReusableView,建立後的文件目錄以下:code
(2) 由於咱們是從xib文件中加載的UICollectionReusableView,因此須要在相應的UICollectionView上進行註冊。若是你是使用的Storyboard, 只須要在Storyboard中指定重用標示符便可。下面的代碼就是在ViewDidLoad中調用註冊UICollectionReusableView的方法。
1 /**
2 * 註冊Header和FooterView
3 * 便於在UICollectionViewDataSource中使用
4 */
5 - (void) registerHeaderAndFooterView {
6 //註冊headerView
7 //獲取含有UICollectionReusableView的Nib文件。
8 UINib *headerNib = [UINib nibWithNibName: @"CollectionHeaderReusableView"
9 bundle: [NSBundle mainBundle]];
10
11 //註冊重用View
12 [self.collectionView registerNib: headerNib
13 forSupplementaryViewOfKind: UICollectionElementKindSectionHeader
14 withReuseIdentifier: @"CollectionHeaderReusableView"];
15
16
17 //註冊FooterView
18 UINib *footerNib = [UINib nibWithNibName: @"CollectionFooterReusableView"
19 bundle:[ NSBundle mainBundle]];
20
21 [self.collectionView registerNib: footerNib
22 forSupplementaryViewOfKind: UICollectionElementKindSectionFooter
23 withReuseIdentifier: @"CollectionFooterReusableView"];
24
25 }
複製代碼
(3)在UICollectionViewDataSource中的設置Supplementary View的方法中經過Header View和Footer View的重用標示符來爲咱們的Section設置Supplementary View,具體代碼以下所示:
1 /**
2 * 設置Setion的Header和Footer(Supplementary View)
3 */
4 - (UICollectionReusableView *)collectionView: (UICollectionView *)collectionView
5 viewForSupplementaryElementOfKind: (NSString *)kind
6 atIndexPath: (NSIndexPath *)indexPath{
7
8 //設置SectionHeader
9 if ([kind isEqualToString: UICollectionElementKindSectionHeader]) {
10
11 UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderReusableView" forIndexPath:indexPath];
12
13 return view;
14 }
15
16 //設置SectionFooter
17 UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionFooterReusableView" forIndexPath:indexPath];
18 return view;
19
20 }
複製代碼
UICollectionViewDataSource中的四個方法在上面都進行了實現,UICollectionViewDataSource主要是負責加載數據源的,包括Section的個數,每一個Section中Cell的個數,每一個Section中Supplementary View的種類。
UICollectionViewDelegateFlowLayout主要是負責顯示的,好比Secion的大小、邊距,Cell的大小邊距,headerView的大小已經FooterView的大小,都是在UICollectionViewDelegateFlowLayout的相應協議的方法來實現的。接下來詳細的介紹一下UICollectionViewDelegateFlowLayout協議中的方法。
1.同一個Section中同一種Cell(經過同一個Cell重用標示符獲取的對象)能夠有不一樣的尺寸,下面的代碼是給Cell定製尺寸。代碼的具體意思是第一個Section中的全部Cell的尺寸是(50,50)。 其他的時(60,60)。
1 #pragma mark <UICollectionViewDelegateFlowLayout>
2 /**
3 * 改變Cell的尺寸
4 */
5 - (CGSize)collectionView: (UICollectionView *)collectionView
6 layout: (UICollectionViewLayout*)collectionViewLayout
7 sizeForItemAtIndexPath: (NSIndexPath *)indexPath{
8
9 if (indexPath.section == 0) {
10 return CGSizeMake(50, 50);
11 }
12
13 return CGSizeMake(60, 60);
14 }
複製代碼
2.改變Section的上下左右邊距--UIEdgeInsetsMake(上, 左, 下, 右),逆時針旋轉。第一個Section的上左下右的邊距都是50, 其他的Section上左下右的邊距是0。具體實現看以下代碼:
1 /**
2 * Section的上下左右邊距--UIEdgeInsetsMake(上, 左, 下, 右);逆時針
3 */
4 - (UIEdgeInsets)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 insetForSectionAtIndex: (NSInteger)section{
7
8 if (section == 0) {
9 return UIEdgeInsetsMake(50, 50, 50, 50);
10 }
11 return UIEdgeInsetsMake(0, 0, 0, 0);
12 }
複製代碼
3.設置每一個Cell的上下邊距的回調以下所示,第一個Section的Cell上下邊距是5.0f, 其他的爲20.0f。
1 /**
2 * Section中每一個Cell的上下邊距
3 */
4 - (CGFloat)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 minimumLineSpacingForSectionAtIndex: (NSInteger)section{
7 if (section == 0) {
8 return 5.0f;
9 }
10 return 20.0f;
11 }
複製代碼
4.設置Cell的左右邊距,第一個Section的Cell左右邊距是5.0f, 其他的爲20.0f。
1 /**
2 * Section中每一個Cell的左右邊距
3 */
4 - (CGFloat)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 minimumInteritemSpacingForSectionAtIndex: (NSInteger)section{
7 if (section == 0) {
8 return 5.0f;
9 }
10 return 20.0f;
11 }
複製代碼
5.設置Header View和Footer View的大小的回調以下。
1 /**
2 * headerView的大小
3 */
4 - (CGSize)collectionView: (UICollectionView *)collectionView
5 layout: (UICollectionViewLayout*)collectionViewLayout
6 referenceSizeForHeaderInSection: (NSInteger)section{
7 return CGSizeMake(200, 50);
8 }
9
10 /**
11 * footerView的大小
12 */
13 - (CGSize)collectionView: (UICollectionView *)collectionView
14 layout: (UICollectionViewLayout*)collectionViewLayout
15 referenceSizeForFooterInSection: (NSInteger)section{
16 return CGSizeMake(200, 50);
17 }
複製代碼
上面的方法就是UICollectionViewDelegateFlowLayout中全部的方法了,負責佈局顯示的。
UICollectionViewDelegate中的代理方法主要是負責Cell的交互的,好比是否高亮,是否選,是否可編輯等,接下來要爲你們詳細的介紹UICollectionViewDelegate中的代理方法。
1.爲了這部分的效果展現,咱們須要對Cell添加一些控件,而且設置其Highlight和Selected的一些狀態。爲Cell添加上ImageView, Cell的高亮狀態和非高亮狀態對應的ImageView上的圖片是不一樣的。再添加一個Button, 併爲Button設置Selected和Default狀態下的圖片,Button的選中和默認狀態由Cell的選中狀態來定。Cell中改變ImageView的圖片的代碼以下所示,函數傳入的參數是當前Cell的高亮狀態,根據高亮狀態來設置ImageView上的Image。(有的小夥伴會問爲何給ImageView在Default狀態和Highlight下設置不一樣的圖片,而後直接改變ImageView的高亮狀態便可。你能夠試一下,達不到預期的效果)
1 - (void) changeHighLightWithBool: (BOOL) highlight{
2
3 NSString *imageName = @"003.jpg";
4
5 if (highlight) {
6 imageName = @"002.jpg";
7 }
8
9 [_highlightImage setImage: [UIImage imageNamed:imageName]];
10 }
複製代碼
2.設置Cell能夠高亮, 返回YES表明Cell能夠高亮,返回NO表明Cell不可高亮。高亮就是觸摸Cell時該Cell變爲高亮狀態,在代碼中的反應就是Cell的Highligth屬性變爲YES。而觸摸結束時,Cell的Highligth屬性就變爲NO。
1 #pragma mark <UICollectionViewDelegate>
2
3 /**
4 * Cell是否能夠高亮
5 */
6 - (BOOL)collectionView: (UICollectionView *)collectionView
7 shouldHighlightItemAtIndexPath: (NSIndexPath *)indexPath{
8
9 return YES;
10
11 }
複製代碼
3.下面這個方法是本身寫的,用來在界面上反應Cell的高亮狀態。 ImageView在當前Cell高亮狀態下和非高亮狀態下所加載的圖片不一樣,因此能夠看出Cell高亮和非高亮。
1 /**
2 * 根據高亮狀態修改背景圖片
3 */
4 - (void) changeHighlightCellWithIndexPaht: (NSIndexPath *) indexPath{
5 //獲取當前變化的Cell
6 CollectionViewCell *currentHighlightCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
7
8 [currentHighlightCell changeHighLightWithBool:currentHighlightCell.highlighted];
9
10 if (currentHighlightCell.highlighted == YES){
11
12 NSLog(@"第%ld個Section上第%ld個Cell變爲高亮",indexPath.section ,indexPath.row);
13 return;
14 }
15
16 if (currentHighlightCell.highlighted == NO){
17 NSLog(@"第%ld個Section上第%ld個Cell變爲非高亮",indexPath.section ,indexPath.row);
18 }
19
20
21 }
複製代碼
4.Cell從非高亮變爲高亮狀態時回調用下面的方法,爲了反映Cell的高亮狀態,咱們去改變一下Cell上ImageView的圖片。
1 /**
2 * 若是Cell能夠高亮,Cell變爲高亮後調用該方法
3 */
4 - (void)collectionView: (UICollectionView *)collectionView
5 didHighlightItemAtIndexPath: (NSIndexPath *)indexPath{
6
7 [self changeHighlightCellWithIndexPath:indexPath];
8 }
9
10
11 /**
12 * 若是Cell能夠高亮,Cell從高亮變爲非高亮調用該方法
13 */
14 - (void)collectionView: (UICollectionView *)collectionView
15 didUnhighlightItemAtIndexPath: (NSIndexPath *)indexPath{
16
17 [self changeHighlightCellWithIndexPath:indexPath];
18
19 }
複製代碼
5.設定Cell是否可選的回調以下所示,Cell被選中時該Cell的Selected爲YES, 取消選中Selected爲NO;
1 /**
2 * Cell是否能夠選中
3 */
4 - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath{
5 return YES;
6 }
複製代碼
1 //設置Cell多選
2 self.collectionView.allowsMultipleSelection = YES;
複製代碼
7.若是在多選狀態下須要支持取消Cell的多選,那麼就去執行下面的方法,並返回YES。就是支持在多選狀態下取消選中狀態。
1 /**
2 * Cell多選時是否支持取消功能
3 */
4 - (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
5 return YES;
6 }
複製代碼
8.下面這個方法是本身封裝的,用來根據Cell的選中狀態來改變Cell上Button的選中狀態,具體代碼實現以下:
1 /**
2 * Cell根據Cell選中狀態來改變Cell上Button按鈕的狀態
3 */
4 - (void) changeSelectStateWithIndexPath: (NSIndexPath *) indexPath{
5 //獲取當前變化的Cell
6 CollectionViewCell *currentSelecteCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
7
8 currentSelecteCell.selectButton.selected = currentSelecteCell.selected;
9
10 if (currentSelecteCell.selected == YES){
11 NSLog(@"第%ld個Section上第%ld個Cell被選中了",indexPath.section ,indexPath.row);
12 return;
13 }
14
15 if (currentSelecteCell.selected == NO){
16 //NSLog(@"第%ld個Section上第%ld個Cell取消選中",indexPath.section ,indexPath.row);
17 }
18
19 }
複製代碼
9.在Cell選中和取消選中時都會調用上面的方法來改變Button的選中狀態,下面是Cell在選中時以及取消選中時所調用的方法:
1 /**
2 * Cell選中調用該方法
3 */
4 - (void)collectionView: (UICollectionView *)collectionView
5 didSelectItemAtIndexPath: (NSIndexPath *)indexPath{
6
7 [self changeSelectStateWithIndexPath:indexPath];
8 }
9
10 /**
11 * Cell取消選中調用該方法
12 */
13 - (void)collectionView: (UICollectionView *)collectionView didDeselectItemAtIndexPath: (NSIndexPath *)indexPath{
14
15 [self changeSelectStateWithIndexPath:indexPath];
16 }
複製代碼
10.下方四個方法是Cell將要出現,Cell出現後,Supplementary View將要出現以及Supplementary View已經出現所調用的方法,具體信息請看下方代碼實現:
1 /**
2 * Cell將要出現的時候調用該方法
3 */
4 - (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){
5 NSLog(@"第%ld個Section上第%ld個Cell將要出現",indexPath.section ,indexPath.row);
6 }
7
8 /**
9 * Cell出現後調用該方法
10 */
11 - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{
12 NSLog(@"第%ld個Section上第%ld個Cell已經出現",indexPath.section ,indexPath.row);
13 }
14
15
16 /**
17 * headerView或者footerView將要出現的時候調用該方法
18 */
19 - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0){
20
21 NSLog(@"第%ld個Section上第%ld個擴展View將要出現",indexPath.section ,indexPath.row);
22
23 }
24
25 /**
26 * headerView或者footerView出現後調用該方法
27 */
28 - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath{
29
30 NSLog(@"第%ld個Section上第%ld個擴展View已經出現",indexPath.section ,indexPath.row);
31
32 }
複製代碼
在UICollectionViewDelegate回調方法中還有三個回調方法是關於Cell編輯的,好比copy, past, cut等操做,具體代碼就不在此贅述了。在Demo中給出了實現方式,主要涉及到UIPasteboard的操做,本篇博客的總體的Demo回分享到Github上,下方是Github上的分享連接,感興趣的小夥伴能夠進行Clone。
你認爲如何?請經過加咱們的交流羣 點擊此處進交流羣 ,來一塊兒交流或者發佈您的問題,意見或反饋。
Github分享連接:github.com/lizelu/Coll…
做者:青玉伏案