IPhone UITableView. Как включить единый буквенный список, такой как Music App?
В музыкальном приложении iPhone, выбрав "Исполнитель", "Песни" или "Альбомы", вы увидите таблицу с вертикальным списком отдельных букв с правой стороны пользовательского интерфейса, который позволяет быстро прокручивать. Как включить эту функцию в своем приложении?
Cheers,
Дуг
Ответы
Ответ 1
Поставьте свои собственные индексные символы:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return[NSArray arrayWithObjects:@"a", @"e", @"i", @"m", @"p", nil];
}
а затем:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString
*)title atIndex:(NSInteger)index {
return <yourSectionIndexForTheSectionForSectionIndexTitle >;
}
Вам понадобятся разделы.
Ответ 2
Что-то еще, что вам нужно рассмотреть, это локализация разделов для каждого языка. Немного поработав, я нашел UILocalizedIndexedCollation
весьма полезным:
- (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
Ответ 3
Я придумал альтернативный подход к обработке одного алфавитного алфавита без использования разделов. Это похоже на Zaph, но вместо того, чтобы получить какую-либо ценность от возврата нового индекса (поскольку у нас всегда будет 1 раздел), мы вычисляем индекс для местоположения первого элемента в массиве, который начинается с определенного символа, затем прокручивается к нему.
Недостатком является то, что это требует поиска массива каждый раз (это абсолютно ужасно?), однако я не заметил никакого отставания или медленного поведения в симуляторе iOS или на моем 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;
}
добавление свойства для хранения последнего выбранного индекса, например
@property (assign, nonatomic) NSInteger previousSearchIndex;
и сохраняя это свойство каждый раз, например:
- (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;
}
и обновить код scrollToRow
, например:
[tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
Сделайте этот метод еще лучше и с приятной анимацией.
Ответ 4
Куча людей спрашивала, можно ли сделать это без секций. Я хотел получить то же самое, и я нашел решение, которое может быть немного теневым и не возвращает значение sectionForSectionIndexTitle, но если вы находитесь в углу и не хотите, чтобы он делал раздел для каждой буквы алфавита, это это верное решение. Извините за любой код нацистов заранее.: 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++;
}
}
Он отлично работает, если вы получаете большой объем данных и секционирование, это займет кучу работы.:) Пытался использовать общие переменные, чтобы вы знали, что я делаю. d_itemsInTable - NSArray из NSDictionaries, который я перечисляю в UITableView.
Ответ 5
Вот модифицированная версия функции Kyle, которая обрабатывает случай нажатия индекса, для которого у вас нет строки:
- (NSInteger)indexForFirstChar:(NSString *)character inArray:(NSArray *)array
{
char testChar = [character characterAtIndex:0];
__block int retIdx = 0;
__block int lastIdx = 0;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
char firstChar = [obj characterAtIndex:0];
if (testChar == firstChar) {
retIdx = idx;
*stop = YES;
}
//if we overshot the target, just use whatever previous one was
if (testChar < firstChar) {
retIdx = lastIdx;
*stop = YES;
}
lastIdx = idx;
}];
return retIdx;
}
Ответ 6
Если вы используете NSFetchedResultsController
, вы можете просто сделать:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [frc sectionIndexTitles];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [frc sectionForSectionIndexTitle:title atIndex:index];
}
Ответ 7
Внедрить методы делегата -sectionIndexTitlesForTableView:
и -tableView:sectionForSectionIndexTitle:atIndex:
Дополнительную информацию см. в документации UITableViewDataSource
.
Ответ 8
Здесь простое решение в Swift, если у вас есть заголовки заголовков в массиве. Если заголовок не найден, он вернет предыдущий индекс в массиве.
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters.flatMap{String($0)}
}
func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
return self.headerTitles.filter{$0 <= title}.count - 1
}
Ответ 9
Если вы используете MonoTouch, переопределите метод SectionIndexTitles (UITableView) в классе UITableViewDataSource. Просто верните массив строк, а подкласс позаботится об остальном.
class TableViewDataSource : UITableViewDataSource
{
public override string[] SectionIndexTitles(UITableView tableView)
{
return new string[] { /*your string values */};
}
}
* просто подсказка для тех из нас, кто использует С# и Mono (.NET) для написания приложений для iPhone.:)