当数据量特别大时,简单地以role进行分段,对实际查找的效率提升并不大。就像上一节开头所说,开发者可以根据球员名字的首字母进行分段,且分成26段。由于段数较多,可以使用UITableView的索引机制,在界面的右侧展示一条垂直的字母列表,使用户可以快速地在段与段之间进行切换。
新建一个继承自SimpleTableViewController的子类名为IndexedTableViewController,头文件声明如下:
#import "HBSimpleTableViewController.h"
#import "ChineseString.h"
#import "pinyin.h" @interface HBIndexedTableViewController : HBSimpleTableViewController
{
//即表示每段的段名,也表示索引表的内容
NSArray *_indexTitles;
}
并且在SimpleTableViewController的数据源的基础上,对其进行改善优化,数据源将会得到重新制作,代码如下:
-(void)initData
{
[super initData]; //将26个字母放进_indexTitles中
//表示段名,也表示索引表的内容
NSMutableArray *arrTmp=[NSMutableArray arrayWithCapacity:];
for (char c='A';c<='Z';c++) {
[arrTmp addObject:[NSString stringWithFormat:@"%c",c]];
}
if (_indexTitles) {
_indexTitles=nil;
} _indexTitles = [[NSArray alloc]initWithArray:arrTmp]; //中文排序
//step1:获取要排序的数组
NSMutableArray *shouldSortArray=[NSMutableArray arrayWithArray:self.datasource]; //step2:获取字符串中文字的拼音首字母并与字符串共同存放
NSMutableArray *chineseStringsArray=[NSMutableArray array];
for (int i=; i<[shouldSortArray count]; i++) {
ChineseString *chineseString=[[ChineseString alloc]init]; HBPlayerInfo *onePlaer=[shouldSortArray objectAtIndex:i]; chineseString.string=[NSString stringWithString:onePlaer.name]; if(chineseString.string == nil)
{
chineseString.string = @"";
} if(![chineseString.string isEqualToString:@""])
{
NSString *pinYinResult=[NSString string];
for (int j=; j<chineseString.string.length; j++) {
NSString *singlePinyinLetter=[[NSString stringWithFormat:@"%c",pinyinFirstLetter([chineseString.string characterAtIndex:j])]uppercaseString]; pinYinResult=[pinYinResult stringByAppendingString:singlePinyinLetter];
}
chineseString.pinYin=pinYinResult;
}
else
{
chineseString.pinYin=@"";
}
[chineseStringsArray addObject:chineseString];
} //step2的输出
NSLog(@"\n\n\n转换为拼音首字母后的NSString数组");
for (int i=; i<[chineseStringsArray count]; i++) {
ChineseString *chineseString=[chineseStringsArray objectAtIndex:i];
NSLog(@"原String:%@----拼音首字母String:%@",chineseString.string,chineseString.pinYin);
} //step3:按照拼音首字母对这些string进行排序
NSArray *sortDescriptors=[NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:@"pinYin" ascending:YES], nil]; [chineseStringsArray sortUsingDescriptors:sortDescriptors]; //step3的输出
NSLog(@"\n\n\n按照拼音首字母后的NSString数组");
for(int i=;i<[chineseStringsArray count];i++){
ChineseString *chineseString=[chineseStringsArray objectAtIndex:i];
NSLog(@"原String:%@----拼音首字母String:%@",chineseString.string,chineseString.pinYin);
} //step4:如果有需要,再把排序好的内容从ChineseString类中提取出来
NSMutableArray *result=[NSMutableArray array];
NSMutableArray *pinYinResult=[NSMutableArray array];
for(int i=;i<[chineseStringsArray count];i++){
[result addObject:((ChineseString*)[chineseStringsArray objectAtIndex:i]).string];
[pinYinResult addObject:((ChineseString *)[chineseStringsArray objectAtIndex:i]).pinYin];
}
//Step4输出
NSLog(@"\n\n\n最终结果:");
for(int i=;i<[result count];i++){
NSLog(@"%@",[result objectAtIndex:i]);
} //得到名字排好序的数据源后,需要将这些球员对象根据名字的首字母,进行分段
NSMutableArray *arrAll = [NSMutableArray arrayWithCapacity:]; //遍历26个字母
for(NSString *aIndexTitle in _indexTitles)
{
arrTmp=[[NSMutableArray alloc]initWithCapacity:]; //遍历球员对象,找到那些名字是当前字母的球员,加到arrTmp中去
for (ChineseString *oneChineseString in chineseStringsArray) {
NSString *pinYin=oneChineseString.pinYin;
NSString *firstPinYin=[pinYin substringToIndex:]; //不区分大小写比较
if([[firstPinYin lowercaseString] hasPrefix:[aIndexTitle lowercaseString]])
{
[arrTmp addObject:oneChineseString];
}
}
[arrAll addObject:arrTmp];
}
//重置数据源,进行赋值 if(_datasource)
{
_datasource=nil;
}
_datasource = [[NSArray alloc] initWithArray:arrAll];
}
数据源操作完,对于UITableView的数据源回调函数,需要为索引机制定做一套
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return _indexTitles.count;
} //每段几行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(!self.datasource)
{
return ;
} NSArray *arrSectionPlayer=[self.datasource objectAtIndex:section];
return arrSectionPlayer.count;
} //索引表内容
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return _indexTitles;
} //索引表与段之间的关联
-(NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
//告诉我们一个段名和该段的序号
//我们需要返回一个对于索引表数组内容的序号
NSInteger count=;
for (NSString *aAlpha in _indexTitles) {
if ([aAlpha isEqualToString:title]) {
return count;
}
count++;
}
return ;
} -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"IndexTableViewCellId";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
} //数据源有两层,需要注意获取特定球员对象的方法
ChineseString *chineseString=nil;
NSArray *arrSectionPlayer = [self.datasource objectAtIndex:indexPath.section];
if(arrSectionPlayer && arrSectionPlayer.count>indexPath.row)
{
chineseString=[arrSectionPlayer objectAtIndex:indexPath.row];
}
if(chineseString)
{
cell.textLabel.text=chineseString.string;
}
return cell;
}
另外,段名并非一定需要实现其数据源回调函数,使用代理回调函数也能够对段名进行配置,代码如下:
#pragma mark-
#pragma mark TableView delegate
//段名高22px高
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 22.0f;
} -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
//使用UILabel来显示段名
NSString *strHeaderTitle = @"";
UILabel *labHeaderView = [[UILabel alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 22.0f)]; if(_indexTitles && section < _indexTitles.count)
{
strHeaderTitle = [_indexTitles objectAtIndex:section];
}
labHeaderView.text = [NSString stringWithFormat:@" %@",strHeaderTitle];
labHeaderView.textColor = [UIColor whiteColor];
labHeaderView.shadowColor = [UIColor grayColor];
labHeaderView.shadowOffset = CGSizeMake(1.0f, 1.0f);
labHeaderView.font =[UIFont fontWithName:@"Helvetica" size:16.0f];
labHeaderView.backgroundColor=[UIColor colorWithRed:200.0f/255.0f green:200.0f/255.0f blue:200.0f/255.0f alpha:1.0f]; return labHeaderView;
}
运行程序,得到如图14.8所示的结果。