iPhone联系app风格的索引表视图实现 [英] iPhone contacts app styled indexed table view implementation
问题描述
我的要求:
我有一个直接的要求,即在索引表视图中按字母顺序列出人名,索引标题是字母表的起始字母(另外还有搜索图标)在顶部,#显示以数字和其他特殊字符开头的misc值。
My Requirement: I have this straight forward requirement of listing names of people in alphabetical order in a Indexed table view with index titles being the starting letter of alphabets (additionally a search icon at the top and # to display misc values which start with a number and other special characters).
到目前为止我做了什么:
1.我正在使用核心数据进行存储,并且last_name被建模为Contacts实体中的String属性
2.我正在使用NSFetchedResultsController来显示已排序的索引表视图。
What I have done so far: 1. I am using core data for storage and "last_name" is modelled as a String property in the Contacts entity 2.I am using a NSFetchedResultsController to display the sorted indexed table view.
完成我的要求的问题:
1.首先,我无法将部分索引标题作为字母表的第一个字母。 Dave在以下帖子中的建议帮助我实现了相同的目标: NSFetchedResultsController包含由字符串的第一个字母创建的部分
我遇到的唯一问题是Dave的建议是我无法将misc命名为分组在#索引下。
The only issue I encountered with Dave' suggestion is that I couldn't get the misc named grouped under "#" index.
我尝试了什么:
1.我尝试为NSString添加自定义比较方法(类别)检查比较和部分是如何进行的,但是在NSSortDescriptor选择器中指定时不会调用自定义方法。
What I have tried: 1. I tried adding a custom compare method to NSString (category) to check how the comparison and section is made but that custom method doesn't get called when specified in the NSSortDescriptor selector.
这是一些代码:
@interface NSString (SortString)
-(NSComparisonResult) customCompare: (NSString*) aStirng;
@end
@implementation NSString (SortString)
-(NSComparisonResult) customCompare:(NSString *)aString
{
NSLog(@"Custom compare called to compare : %@ and %@",self,aString);
return [self caseInsensitiveCompare:aString];
}
@end
获取数据的代码:
NSArray *sortDescriptors = [NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"last_name"
ascending:YES selector:@selector(customCompare:)] autorelease]];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext sectionNameKeyPath:@"lastNameInitial" cacheName:@"MyCache"];
您能告诉我我缺少什么以及如何完成要求吗?
Can you let me know what I am missing and how the requirement can be accomplished ?
推荐答案
在这个问题上,这是一个非常低效的首次通过,我最终将重写。但希望这会对你有所帮助。
This is a really inefficient first-pass at this problem, which I am going to rewrite eventually. But hopefully this will help you.
这样做的想法是保证在点击标准部分索引视图时返回真正的表部分索引。标准截面索引视图应具有用于搜索的放大镜图标,用于非字母部分的散列标记(#)以及用于字母部分的字母A到Z.
The idea of this is to "guarantee" getting a real table section index back when tapping a "standard" section index view. A standard section index view should have a magnifying lens icon for search, a hash mark (#) for non-alphabetical sections, and letters A through Z for alphabetical sections.
无论实际部分有多少,或者它们是由什么部分构成的,都会显示此标准视图。
This standard view is presented regardless of how many real sections there are, or what they are made of.
最终,此代码将截面视图索引映射到获取的结果控制器中的实际存在的字母部分名称路径,或映射到实际存在的非字母(数字)部分,或映射到表头中的搜索字段。
Ultimately, this code maps section view indices to real-existing alphabetic section name paths in the fetched results controller, or to real-existing non-alphabetic (numerical) sections, or to the search field in the table header.
用户只会在每次触摸部分索引时偶尔重新创建部分索引映射数组( _idxArray
),但是在每次触摸时重新创建阵列显然是低效的,并且可以调整以缓存预先计算的结果。
The user will only occasionally recreate the section index mapping array (_idxArray
) on each touch of the section index, but recreating the array on each touch is obviously inefficient and could be tweaked to cache pre-calculated results.
有很多地方可以开始收紧这个:我可以将 sectionIndexTitleLetters
静态字符串全部大写例如,开始。不过,它在3GS手机上足够快,所以我最近没有重新考虑过这个问题。
There are a lot of places to start tightening this up: I could make the sectionIndexTitleLetters
static string all uppercase from the start, for example. It's fast enough on a 3GS phone, though, so I haven't revisited this recently.
标题中:
static NSString *sectionIndexTitleLetters = @"abcdefghijklmnopqrstuvwxyz";
在表视图数据源的实现中:
In the implementation of the table view data source:
- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tv {
if (tv != searchDisplayController.searchResultsTableView) {
NSMutableArray *_indexArray = [NSMutableArray arrayWithCapacity:([sectionIndexTitleLetters length]+2)];
[_indexArray addObject:@"{search}"];
[_indexArray addObject:@"#"];
for (unsigned int _charIdx = 0; _charIdx < [sectionIndexTitleLetters length]; _charIdx++) {
char _indexChar[2] = { toupper([sectionIndexTitleLetters characterAtIndex:_charIdx]), '\0'};
[_indexArray addObject:[NSString stringWithCString:_indexChar encoding:NSUTF8StringEncoding]];
}
return _indexArray;
}
return nil;
}
- (NSInteger) tableView:(UITableView *)tv sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
if (tv != searchDisplayController.searchResultsTableView) {
if (index == 0) {
//
// This is the search bar "section"
//
[currentTableView scrollRectToVisible:[[currentTableView tableHeaderView] bounds] animated:YES];
return -1;
}
else if (index == 1) {
//
// This is the "#" section, which covers non-alphabetic section headers (e.g. digits 0-9)
//
return 0;
}
else {
//
// This is a bit more involved because the section index array may contain indices that do not exist in the
// fetched results controller's sections->name info.
//
// What we are doing here is building a "fake-index" array that will return a real section index regardless of
// whether the section index title being touched exists or not.
//
// The fake array will be of length of the section index title array, and each index will contain an unsigned
// integer from 1 to {numOfRealSections}.
//
// The value this array returns will be "nearest" to the real section that is in the fetched results controller.
//
NSUInteger _alphabeticIndex = index-2;
unsigned int _idxArray[26];
for (unsigned int _initIdx = 0; _initIdx < [sectionIndexTitleLetters length]; _initIdx++) {
_idxArray[_initIdx] = [[fetchedResultsController sections] count] - 1;
}
unsigned int _previousChunkIdx = 0;
NSNumberFormatter *_numberFormatter = [[NSNumberFormatter alloc] init];
NSLocale *_enUSLocale = [[NSLocale alloc] initWithLocaleIdentifier: @"en_US"];
[_numberFormatter setLocale:_enUSLocale];
[_enUSLocale release];
for (unsigned int _sectionIdx = 0; _sectionIdx < [[fetchedResultsController sections] count]; _sectionIdx++) {
NSString *_sectionTitle = [[[fetchedResultsController sections] objectAtIndex:_sectionIdx] name];
if (![_numberFormatter numberFromString:_sectionTitle]) {
// what's the index of the _sectionTitle across sectionIndexTitleLetters?
for (unsigned int _titleCharIdx = 0; _titleCharIdx < [sectionIndexTitleLetters length]; _titleCharIdx++) {
NSString *_titleCharStr = [[sectionIndexTitleLetters substringWithRange:NSMakeRange(_titleCharIdx, 1)] uppercaseString];
if ([_titleCharStr isEqualToString:_sectionTitle]) {
// put a chunk of _sectionIdx into _idxArray
unsigned int _currentChunkIdx;
for (_currentChunkIdx = _previousChunkIdx; _currentChunkIdx < _titleCharIdx; _currentChunkIdx++) {
_idxArray[_currentChunkIdx] = _sectionIdx - 1;
}
_previousChunkIdx = _currentChunkIdx;
break;
}
}
}
}
[_numberFormatter release];
return (NSInteger)_idxArray[_alphabeticIndex];
}
}
return 0;
}
这篇关于iPhone联系app风格的索引表视图实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!