---恢復內容開始---
怎樣在UICollectionView中添加Header和footer
在前面我們已經學過,每個collection view都必須有數據源為其提供內容。它的責任是為collection views完成以下的事情:
-
控制collection view的section數目
-
每個section中的item的個數
-
為特定的數據項提供cell view
顯然,簡單的Recipe app,我們在前面的教程中包含了其中一個部分,在這里我們將繼續講講collection view並且告訴你如何利用不同的section組織items,你將會學到怎樣為collection view添加header視圖和footer視圖。
如果你沒有看過前面的教程,建議你去看一看前面的教程,或者你可以到這里下載here。
Split Recipes into Two Sections in UICollectionView
在這個簡單的程序中,RecipeCollectionViewController是集合視圖的數據源對象,為了把視圖分成兩個部分,我們需要有一些變化,接下來我們完成:
起先,recipeImages數組是存儲所有recipes的名稱,因為我們想把recipes分成兩組,我們要修改我們 的代碼,並使用簽到數組來存儲不同的recipe,也許你還不明白啥是嵌入的數組,下面的圖片會讓你明白的。第一組包含主要的圖像,而另一個為drink 和dessert。頂級數組(即recipeImages)包含兩個數組,每個數組部分的特定區域包含特定的data items。
讓我們開始編寫代碼,在RecipeCollectionViewController.m中初始化"recipeImages"數組,並在viewDidload方法中寫下面的方法:
- (void)viewDidLoad
{
[super viewDidLoad];
//Initialize recipe image array
NSArray *mainDishImages = [NSArray arrryWithObjects:@"egg_benedict.jpg", @"full_breakfast.jpg", @"ham_and_cheese_panini.jpg", @"ham_and_egg_sandwich.jpg", @"hamburger.jpg", @"instant_noodle_with_egg.jpg", @"japanese_noodle_with_pork.jpg", @"mushroom_risotto.jpg", @"noodle_with_bbq_pork.jpg", @"thai_shrimp_cake.jpg", @"vegetable_curry.jpg", nil];
NSArray *drinkDessertImages = [NSArray arrayWithObjects:@"angry_birds_cake.jpg", @"creme_brelee.jpg", @"green_tea.jpg", @"starbucks_coffee.jpg", @"white_chocolate_donut.jpg", nil];
recipeImages = [NSArray arrayWithObjects:mainDishImages,drinkDesserImages,nil];
}
上面的代碼將recipes images分成兩組。接下來,修改"numberOfIntemsInSecion:"方法來返回,每個secions中的items數目:
- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSecion:(NSInteger)section
{
return [[recipeImages objectAtIndex:sectin]count];
}
接下來我們按照下面的方法修改"cellForItemAtIndexPath:"方法
- (UICollectionVIewCell *)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"Cell";
RecipeViewCell *cell = (RecipeViewCell *)[collectionView dequeueReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imagedNamed:[recipeImages[indexPath.section] objectAtIndex:indexPath.row]];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"photo-frame-2.png"]];
return cell;
}
你可以和以前的代碼比較以下,你就會知道只有一樣是唯一的變化。我們首先檢索該數組的section number然后從section中獲取具體的items。
最后,怎樣給collection view實現兩個section,這個可以通過方法調用下面的方法來完成即:在RecipeCollectionViewController.m中的 numberOfSectionsInCollectionView方法,在collectin View中返回section中的數量。
- (NSInteger)numberOfSectionsInCollectionVIew:(UICollectionView *)collectionView
{
return [recipeImages count];
}
現在運行你的app,你會在屏幕上看到下面的顯示
Tweak the Margin of Your Content using Section Insets
(利用Section Insets)
程序是完成了,但是你是否覺得看起來並不怎么順眼呢?圖像的第一部分的最后一行和第二部分的第一樣靠的太近。我們可以使用插入圖到內容周圍的空間中來改變一些格局,通過下圖你可以比較直觀 的看到影響:
你可以利用UIEdgeInsetsMake來完成插入:
insert = UIEdgeInsetsMake(top,left,botton,right);
在我們的Recipe app中我們只能在兩個section之間添加空間。在RecipeCollectionViewController.m文件中的ViewDidLoad方法中,添加下面的方法:
UICollectionViewFlowLayout *collectionViewLayout = (UICollectionViewFlowLayout *)self.collectionViewFlowLayout;
collectionViewLayout.sectionInset = UIEdegeInsetsMake(20,0,0,0);
上面的代碼實現了在collection view中創建和添加插入。現在我們運行程序,你將會看到下面的 圖像顯示,我們在兩個section之間增加了一些空間。
添加頭部和底部視圖
現在我們進一步調整應用程序,讓其更酷。讓我們來給應用程序添加頭部和底部視圖,我們利用UICollectionViewFlowLayout來實現 這一點。這里的header和footer視圖可以被稱為流布局的補充。在默認情況下,這些視圖是在流布局中禁用的。但可以通過下面幾件事情來配置 header和footer視圖:
-
為了盡量保持簡單,所以我們可以選擇storyboard來實現(當然這不是必須的,你同樣可以使用代碼來實現這一點)
-
實現 UICollectionViewDataSource協議的 collectionView:viewForSupplementaryElementOfKind 方法,並通過這個方法來實現補充試圖在collection view中顯示。
在Storyboard中設計Header和Footer
首先download the header/footer background images並且添加到Xcode工程中。
到Storyboard中,選擇collection view controller中的"Collection View"。在Attributes inspector中,選擇"Section Header"和"Section Footer",一旦選中你就會在屏幕中看到下面的的顯示:
在header和footer之間默認為空,我們會用storyboard來設計視圖。header view是專門用來顯示一個部分的標題,而底部視圖只顯示靜態橫幅圖片。利用storyboard,從對象庫中拖出image view並在其上面添加一個標簽。設置字體顏色為白色,底部視圖只需添加一個image view。如圖:
選中footer view中的image view,在Attributes inspector中命名背景圖片為"footer_banner.png"
最重要的是,我們必須為header和footer view指定一個標識符。這個標示符將會被用於代碼識別圖片名稱。在Atteributes inspector中設置header view的identifier為“HeaderView”,同樣的把footer view的identifier設置為“FooterView”。
為Header View添加新類
在默認情況下,header和footer view和UICollectionResuable類相關聯。為了在header view中顯示我們需要的背景和標題,我們必須創建一個新的繼承自UICollectionResuableView的類,我們可以命名為 RecipeCollectionHeaderView。
在storyboard的Identifier inspector中的sustom class設置為“RecipeCollectionHeaderView”。按住Ctrl鍵,單機header中的image view,並拖向RecipeCollectionHeaderView.h中插入一個Outlet 變量。命名變量為"backgroundImage"。重復同樣的步驟對UILabel實現,然后命名為"title"。
實現viewForSupplementaryElementOfKind方法
如果你嘗試運行應用程序,你可能不會看到header和footer,這是因為我們還沒有實現"viewFOrSupplementaryElementOfKind:"方法。選擇“RecipeCollectionViewController”,並添加import語句。
#import "RecipeCollectionHeaderView.h"
下面就是實現viewforSupplementaryElementOfKind方法的代碼:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *reusableview = nil;
if (kind == UICollectionElementKindSectionHeader){
RecipeCollectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];
NSString *title = [[NSString alloc] initWithFormat:@"Recipe Group #%i",indexPath.section +1];
headerView.title.text = title;
UIImage *headerImage = [UIImage imageNamed:@"header_banner.png"];
headerView.backgroundImage.image = headerImage;
reusableView = headerView;
}
if (kind == UICollectionElementKindSectionFooter){
UICollectionReusableView *footerview = [collectionView dequeueResuableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath];
reusableview = footerview;
}
return reusableview;
}
上 面的代碼告訴它頁眉/頁腳視圖應該在每個部分中使用collect view。我們首先確定該集合視圖要求header或footer view。這可以通過使用一種變量來完成。對於頭來看,我們出列header view(使用dequeueReusableSupplementaryViewOfKind :方法),並設置適當的標題和圖像。正如你可以從兩個if之間的代碼,我們使用我們之前分配給獲得header/footer view標識符。
現在運行代碼,我們可以看到運行的結果:
---恢復內容結束---