在之前的文章UITableView 的資料設定方式一文中,已經示範如何在 UITableView 中設定所要顯示的資料,以及分別顯示這些資料的細節,但是如果資料比數太多時該怎麼辦?你可以參考本篇文章的做法,將資料做分類的處理,並且建立快速索引,讓使用者能以最短的時間找到所需要的資料。
資料分類的概念
動態表格的內容多半是存放在陣列當中方便資料的存取,如果你有好幾類不同比的資料,你可以將這些資料分別存放在不同的陣列裡,最後再使用一個 NSMutableArray 將這些存放不同資料的陣列包起來,之後我們只要針對這個 NSMutableArray 做操作即可。(以下是沿用之前文章的程式碼做修改)
//資料初始化
roleArray = [[NSArray alloc] initWithObjects:@"野蠻人", @"法師", @"弓箭手", @"盜賊", @"德魯伊", @"騎士", nil];
monsterArray = [[NSArray alloc] initWithObjects:@"哥布林戰士", @"哥布林護衛", @"哥布林軍官", @"哥布林王", @"黑暗德魯伊", @"狼人", @"傀儡護衛", @"傀儡領主", @"蜘蛛", @"蝙蝠", nil];
heroicaArray = [[NSMutableArray alloc] initWithObjects:roleArray, monsterArray, nil];
UITableView Sections 的設定
如果要將資料作分類顯示,可以使用以下的內建方法函式,並回傳一個 NSInteger,告訴 UITableViewController 你想將資料分成幾類。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [heroicaArray count];
}
程式碼到此就已經算是完成資料的分類,後續的動作就是要顯示這些分類好的資料,大致的程式碼都和之前的文章差不多,只是操作的物件不同,可以透過方法函式所得到的 section 參數,決定於目前是要處理那一類的資料。
//設定每一類的資料筆數
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[heroicaArray objectAtIndex:section] count];
}
//設定每一類的資料內容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//製作可重復利用的表格欄位Cell
static NSString *CellIdentifier = @"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//設定欄位的內容與類型
cell.textLabel.text = [[heroicaArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
分類標題與快速索引
分類的標題可以家在分類的開頭或是結尾,同樣是透過方法函式所得到的 section 參數,來確認目前所在的分類。
//設定分類開頭標題
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
switch (section) {
case 0:
return @"英雄角色";
break;
case 1:
return @"怪物角色";
break;
default:
return @"";
break;
}
}
//設定分類結尾標題
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
}
另外,建立類似電話簿的快速索引,則可以透過下列內建方法函式,回傳一個快速索引的陣列,陣列內容的順序,就是你分類的順序。
//建立快速索引
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
NSArray *index = [[NSArray alloc] initWithObjects:@"英雄", @"怪物", @"武器", @"道具", @"戰利品", @"其他", nil];
return index;
}
比較好的做法
在上述分類標題與快速索引的部分,使用 switch 與靜態的數值來做設定,其實這不是很恰當的做法,尤其當你的資料筆數非常龐大的時候,比較好的建議是將這些資訊同樣放入陣列裡面,且動態存取它們,來完成設定標題與建立索引陣列。
另外要注意的是,雖然是好幾類不同的資料,但是他們最好還是能擁有相同的屬性,即使該屬性為 nil。例如 A 類型的資料有顏色屬性,但是 B 類型沒有或是不需要,但是仍需為 B 類型的資料保留顏色屬性,即使它們的值都是 nil,這樣的觀念有點類似於多型 Polymorphism,這樣不但可以減少程式碼的撰寫,對於表格內的資料也能保持一致性。
我依照了這篇教學文章以及上一篇"UITableView 的資料設定方式"來做這個APPS,完成后在模擬器的MasterView所顯示的資料一切正常,當點選“英雄角色”時,都能跳去相關的DetailViewController;但當點選“怪物角色”時,就不能跳去相關的DetailViewController。例如當我點選“哥布林戰士”時,就會跳去“野蠻人”的DetailViewController,當我點選“哥布林護衛”時,就會跳去“法師”的DetailViewController,如此類推。我認為是上一篇的”detailView“在傳遞參數時的方法需要作出修改才能應用在這篇教學。但我嘗試了很久也未能成功,希望你能給予我一些提示或解決方法,謝謝^^
回覆刪除Kwai Lam 您好:
刪除本篇的內容是著重在分類與索引的部份,如果您只是按照上述的程式碼實作,的確會產生這樣的問題。
回到您問題的陳述,不難發現不管選擇哪一個 Sections 內的 Cell ,都只會對應到同一個陣列內的數值,
原因很簡單,在前一篇文章「UITableView 的資料設定方式」中,我們只有針對單一陣列的內容去做設定,因為這時我們的資料內容很單純,只有單單一個 roleArray,但是到本篇文章時,我們已經將資料內容擴大,並且使用一個 NSMutableArray 「heroicaArray」來放置每個 Sections 的資料,因此在 heroicaArray 中會有兩個元素,一個是 roleArray,而另一個是 monsterArray。
解決問題的方法,只要將 Sections 的觀念放在之其那篇文章中即可。
ex:(取得 Sections 的方法)你可以將它應用在 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 方法函式中:
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
NSString *objectName = [[heroicaArray objectAtIndex:path.section] objectAtIndex:path.row];
[segue.destinationViewController setDetailItem:objectName];
成功了,感謝你詳細的講解!
刪除不用客氣啦!
刪除