在APP開發中,我們經常會去做一個通訊錄。所有做iOS開發的都知道這玩意兒應該用UITableView
來做。但是,如何將數據分組排序總是一個比較麻煩的問題,這里提供我個人的解決方法供大家參考。
排序的目標
因為要是用UITableView,所以我們的數據源應該是這樣一個數組:數組dataArray擁有27個子數組subArray,前26個subArray存儲以A到Z開頭的聯系人,第27個數組存儲不以字母開頭的聯系人,也就是我們常見的#。另外我們需要一個titileArray數組用來作為數組右側的索引和每個section的標題。
再次明確一下我們的目標:一個dataArray,包含27個subArray,另外需要一個titleArray。
獲取首字母
如果我們的聯系人都是英文名,這一步就很簡單,但是有中文名怎么辦呢? 沒關系,OC其實給我們提供了一個方法用來將漢字轉化成拼音,這樣我們就能很方便的取到首字母了。
我們首先寫下獲取首字母的方法
- (NSString *)returnFirstWordWithString:(NSString *)str
{
NSMutableString * mutStr = [NSMutableString stringWithString:str];
//將mutStr中的漢字轉化為帶音標的拼音(如果是漢字就轉換,如果不是則保持原樣)
CFStringTransform((__bridge CFMutableStringRef)mutStr, NULL, kCFStringTransformMandarinLatin, NO);
//將帶有音標的拼音轉換成不帶音標的拼音(這一步是從上一步的基礎上來的,所以這兩句話一句也不能少)
CFStringTransform((__bridge CFMutableStringRef)mutStr, NULL, kCFStringTransformStripCombiningMarks, NO);
if (mutStr.length >0) {
//全部轉換為大寫 取出首字母并返回
NSString * res = [[mutStr uppercaseString] substringToIndex:1];
return res;
}
else
return @"";
}
按首字母分組排序
前面說過,我們的27分別代表從A到Z再加上#,那么我們這一步就是要將上一步獲得的首字母所對應的聯系人放到相應的數組中去(比如把 奔跑的炸雞放到第二個數組,因為它代表B開頭的聯系人)。
那我們需要寫27個if語句嗎?
當然不是,我們有更簡單的方法,但是我們需要先回憶兩個小知識點
- 記得A到Z對應的ASCⅡ碼嗎?是65到90。在Unicode編碼中,A到Z對應的也是65到90。
- 記得在C語言中,一個
char
類型其實就是一個字節的int
類型嗎?如果將char
作為int
去取值,那么A就是65,Z就是90。
通過以上兩點我們就可以將拿到首字母的聯系人直接放到對應的數組,無需任何比較
接下來是代碼
- (void)dealDataWithArray:(NSArray *)array
{
NSMutableArray * tmpArray = [[NSMutableArray alloc]init];
for (NSInteger i =0; i <27; i++) {
//給臨時數組創建27個數組作為元素,用來存放A-Z和#開頭的聯系人
NSMutableArray * array = [[NSMutableArray alloc]init];
[tmpArray addObject:array];
}
for (AddressModel * model in array) {
//AddressMode是聯系人的數據模型
//轉化為首拼音并取首字母
NSString * nickName = [FunctionModule returnFirstWordWithString:model.nickname];
int firstWord = [nickName characterAtIndex:0];
//把字典放到對應的數組中去
if (firstWord >= 65 && firstWord <= 90) {
//如果首字母是A-Z,直接放到對應數組
NSMutableArray * array = tmpArray[firstWord - 65];
[array addObject:model];
}
else
{
//如果不是,就放到最后一個代表#的數組
NSMutableArray * array =[tmpArray lastObject];
[array addObject:model];
}
}
//此時數據已按首字母排序并分組
//遍歷數組,刪掉空數組
for (NSMutableArray * mutArr in tmpArray) {
//如果數組不為空就添加到數據源當中
if (mutArr.count != 0) {
[self.dataArray addObject:mutArr];
AddressModel * model = mutArr[0];
NSString * nickName = [FunctionModule returnFirstWordWithString:model.nickname];
int firstWord = [nickName characterAtIndex:0];
//取出其中的首字母放入到標題數組,暫時不考慮非A-Z的情況
if (firstWord >= 65 && firstWord <= 90) {
[self.titleArray addObject:nickName];
}
}
}
//便利結束后,兩個數組數目不相等說明有除大寫字母外的其他首字母
if (!(self.titleArray.count == self.dataArray.count)) {
[self.titleArray addObject:@"#"];
}
//刷新tableView
[self.tableView reloadData];
}
效果展示
一些不算坑的坑
1.右側的索引列表,網上給出的答案是實現 - (NSArray *)titleArrayAtIndexes:(NSIndexSet *)indexes
方法,但是實際上這個方法已經無效了,現在應該去實現
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return self.titleArray;
}
2.還是索引,默認的索引是文字是藍色的,還會打一個白色的半透明圖層,這兩個東西其實是可以直接設置的。代碼如下:
//設置索引文字顏色
self.tableView.sectionIndexColor = ColorFromRGB(0x646464);
//設置索引背景顏色
self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
3.section的那種懸浮效果,只有當tableView的風格是Plain的時候才會有。
4.tableView底部多余空白Cell可以通過設置TableViewFooter解決
self.tableView.tableFooterView = [UIView new];
結語
最近事情有點多,拖了很久才寫。
這里只是提供個人使用的方法,如果有錯誤之處歡迎指出。
如果我的文章對您有幫助,請點贊或評論。
我們下篇文章見!