在涉及到联系人或者选择城市这些列表的时候,经常会看到这种效果:
这是一组数据源 [@"阿福",@"宝宝",@"大明", @"孙s", @"李龙", @"冠军", @"温馨", @"赵长明",@"cs", @"bg", @"lk", @"sg", @"##号"]。
这个效果有两个关键问题,第一是展示右侧索引,并且要提供点击每个字母的事件。第二是将数据源按字母分成不同的组,并在tableview的代理方法中返回。
针对第一个问题, 事实上,伟大的UITableView已经封装好了这个效果,直接调用Api就可以实现右侧的索引效果,并且可以指定文字颜色,索引的背景颜色,以及点击每个索引字母所触发的事件。
第二个问题,Apple当然也提供了解决办法,因为这个毕竟是一个太常见的需求了。从iOS3.0开始,苹果提供了一个UILocalizedIndexedCollation对象来管理索引。它就是配合tableview使用的。
这个对象很强大,提供了返回包含A-Z 字母的数组,和返回汉字的拼音首字母 以及按汉字的拼音首字母进行排序的功能,真是太实用了。有了这个对象,结合tableview的Api,实现这个效果简直不需要多少行代码。
先按官方文档做个介绍:
- UILocalizedIndexedCollation
An object that provides ways to organize, sort, and localize the data for a table view that has a section index
一个提供了组织 排序和本地化含有右侧索引的tableView数据源的对象 - Overview
Table views with section indexes are ideal for displaying and facilitating the access of data composed of many items organized by a sequential ordering scheme such as the alphabet. Users tap an index title to jump to the corresponding section. The initial table view of the Phone/Contacts application on the iPhone is an example. Note that the section titles can be different than the titles of the index. The table view’s data source uses the collation object to provide the table view with input for section titles and section index titles.
To prepare the data for a section index, your table-view controller creates a indexed-collation object and then, for each model object that is to be indexed, calls sectionForObject:collationStringSelector:. This method determines the section in which each of these objects should appear and returns an integer that identifies the section. The table-view controller then puts each object in a local array for its section. For each section array, the controller calls the sortedArrayFromArray:collationStringSelector: method to sort all of the objects in the section. The indexed-collation object is now the data store that the table-view controller uses to provide section-index data to the table view, as illustrated in Listing 1.
带有section indexes的TableViews适用于显示和管理一些这样的数据源,这些数据源往往可以按一系列标志进行排序,例如首字母。用户点击index title就可以跳转到对应的section。手机上的联系人应用就是一个例子.注意section titles可以和index 的titles不同。tableview 使用数据源提供section titles和section index titles
为了准备段索引的数据,table-view控制器创建一个indexed-collation对象,然后对每一个要被索引的对象,调用sectionForObject:collationStringSelector:方法,这个方法会决定该对象应该出现在哪个section并返回一个integer来标志这个section.table view控制器会将每个对象加入到section对应的数组。对于section的每一个数组,控制器可以调用sortedArrayFromArray:collationStringSelector方法对section的数组里的所有对象进行局部排序。indexed-collation对象现在是数据容器,table-view控制器用它来向table view提供段索引数据,如下面所示:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:section];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex
}
直接上代码
定义了一个模型,name接收数据源的字符串。
控制器中首先定义全局变量
@interface ViewController () <UITableViewDelegate,UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableview;
@property (nonatomic, strong) NSMutableArray *sectionArr;
@end
@implementation ViewController {
//全局索引集合
UILocalizedIndexedCollation *collation;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *testArr = @[@"阿福",@"宝宝",@"大明", @"孙s", @"李龙", @"冠军", @"温馨", @"赵长明",@"cs", @"bg", @"lk", @"sg", @"##号"];
NSMutableArray *personArr = [NSMutableArray arrayWithCapacity:testArr.count];
for (NSString *str in testArr) {
Object *v = [[Object alloc] init];
v.name = str;
[personArr addObject:v];
}
//初始化UILocalizedIndexedCollation对象
collation = [UILocalizedIndexedCollation currentCollation];
//这个对象中包含26个大写字母A-Z 和 #
NSArray *titles = collation.sectionTitles;
//定义一个二维数组,数组中的共有27个元素,每个元素又是一个数组,分别对应字母A、B、C、D...#的数据
NSMutableArray *secionArray = [NSMutableArray arrayWithCapacity:titles.count];
//向二维数组中添加小数组
for (int i = 0; i < titles.count; i++) {
NSMutableArray *subArr = [NSMutableArray array];
[secionArray addObject:subArr];
}
for (Object *v in personArr) {
//这个方法会根据@selector中的方法返回的字符串的拼音首字母,找到这个首字母对应的下标index
NSInteger section = [collation sectionForObject:v collationStringSelector:@selector(name)];
//根据index取出二维数组中的一维数组数组元素
NSMutableArray *subArr = secionArray[section];
//将这个对象加入到一维数组数组中 也就是以字母A开头的对象如阿福会被加入到A字母所对应数组,其他字母同理
[subArr addObject:v];
}
//遍历二维数组,取出每一个一维数组,在对数组中的对象按照字母进行下排序。
for (NSMutableArray *arr in secionArray) {
NSArray *sortArr = [collation sortedArrayFromArray:arr collationStringSelector:@selector(name)];
[arr removeAllObjects];
[arr addObjectsFromArray:sortArr];
}
_sectionArr = secionArray;
//定义tableview右侧section的外观
//文字颜色
_tableview.sectionIndexColor = [UIColor blackColor];
//背景颜色
_tableview.sectionIndexBackgroundColor = [UIColor clearColor];
//触摸section区域时候的背景颜色 _tableview.sectionIndexTrackingBackgroundColor = [UIColor greenColor];
_tableview.sectionIndexMinimumDisplayRowCount = 13;
}
tableview的delegate和datasource方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [collation sectionTitles].count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[_sectionArr objectAtIndex:section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellid = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellid];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellid];
}
Object *v = [[_sectionArr objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.textLabel.text = v.name;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return [_sectionArr[section] count] == 0 ? 0 : 15;
}
/**返回右侧索引所包含的内容*/
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView {
NSMutableArray *sections = [collation.sectionTitles mutableCopy];
//往索引数组的开始处添加一个放大镜🔍 放大镜是系统定义好的一个常量字符串表示UITableViewIndexSearch 当然除了放大镜外也可以添加其他文字
[sections insertObject:UITableViewIndexSearch atIndex:0];
return sections;
}
//返回每个section的title
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[collation sectionTitles] objectAtIndex:section];
}
//点击右侧索引后跳转到的section
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return 0;
}
代码地址 :https://gitee.com/helantage/tableviewYouCeSuoYinXiaoGuo.git
PS:
感觉tableview的索引条将表视图往左边挤了一点?别担心,只是颜色问题。只要如此设置即可
//索引条背景的颜色(清空颜色就不会感觉索引条将tableview往左边挤)
[_tableView setSectionIndexBackgroundColor:[UIColor clearColor]];
//索引条文字的颜色
[_tableView setSectionIndexColor:[UIColor darkGrayColor]];