iPhone UITableView. How do turn on the single letter alphabetical list like the Music App?
Solution 1:
Supply your own index characters:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return[NSArray arrayWithObjects:@"a", @"e", @"i", @"m", @"p", nil];
}
and then:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString
*)title atIndex:(NSInteger)index {
return <yourSectionIndexForTheSectionForSectionIndexTitle >;
}
You will need sections.
Solution 2:
Something else you have to consider is localizing the sections for each language. After digging around a bit, I found UILocalizedIndexedCollation
to be quite useful:
- (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:index];
}
https://developer.apple.com/documentation/uikit/uilocalizedindexedcollation
Solution 3:
I came up with an alternative approach to handling a single letter alphabet list without using sections. It's similar to Zaph's answer but instead of getting any value from returning a new index (since we'll always have 1 section), we calculate the index for the location of the first item in the array that begins with a certain character, then scroll to it.
The downside is this requires searching the array every time (is this absolutely terrible?), however I didn't notice any lag or slow behavior in the iOS simulator or on my iPhone 4S.
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return[NSArray arrayWithObjects:@"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z", nil];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
NSInteger newRow = [self indexForFirstChar:title inArray:self.yourStringArray];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:newRow inSection:0];
[tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
return index;
}
// Return the index for the location of the first item in an array that begins with a certain character
- (NSInteger)indexForFirstChar:(NSString *)character inArray:(NSArray *)array
{
NSUInteger count = 0;
for (NSString *str in array) {
if ([str hasPrefix:character]) {
return count;
}
count++;
}
return 0;
}
adding property to store last selected index like
@property (assign, nonatomic) NSInteger previousSearchIndex;
and storing this property every time like:
- (NSInteger)indexForFirstChar:(NSString *)character inArray:(NSArray *)array
{
NSUInteger count = 0;
for (NSString *str in array) {
if ([str hasPrefix:character]) {
self.previousSearchIndex = count;
return count;
}
count++;
}
return self.previousSearchIndex;
}
and updating scrollToRow
code like:
[tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
Do this method even better and with nice animation.
Solution 4:
A bunch of people asked if it was possible to do this without sections. I wanted the same thing and I found a solution which might be a little shady and doesn't return a value to sectionForSectionIndexTitle but if you are in a corner and don't want to have to make a section for every letter of the alphabet this is a sure fix. Sorry to any code Nazis in advance. :P
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
if (thisTableDataIsShowing)
{
NSMutableArray *charactersForSort = [[NSMutableArray alloc] init];
for (NSDictionary *item in d_itemsInTable)
{
if (![charactersForSort containsObject:[[item valueForKey:@"character_field_to_sort_by"] substringToIndex:1]])
{
[charactersForSort addObject:[[item valueForKey:@"character_field_to_sort_by"] substringToIndex:1]];
}
}
return charactersForSort;
}
return nil;
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
BOOL found = NO;
NSInteger b = 0;
for (NSDictionary *item in d_itemsInTable)
{
if ([[[item valueForKey:@"character_field_to_sort_by"] substringToIndex:1] isEqualToString:title])
if (!found)
{
[d_yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:b inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
found = YES;
}
b++;
}
}
It works great if you are getting a large amount of data and sectioning it would take a bunch of work. :) Tried to use generic variables so you knew what I was doing. d_itemsInTable is an NSArray of NSDictionaries that I'm listing out to the UITableView.