W aplikacji muzycznej na iPhone'a wybranie Artist, Songs lub Albums przedstawia tableView z pionową listą pojedynczych liter po prawej stronie interfejsu użytkownika, która umożliwia szybkie przewijanie. Jak włączyć tę funkcję w mojej aplikacji?
Pozdrawiam, Doug
ios
iphone
objective-c
uitableview
dugla
źródło
źródło
Coś jeszcze, co musisz wziąć pod uwagę, to zlokalizowanie sekcji dla każdego języka. Po trochę poszperania okazało się,
UILocalizedIndexedCollation
że jest całkiem przydatny:- (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
źródło
Wymyśliłem alternatywne podejście do obsługi listy składającej się z pojedynczych liter bez użycia sekcji. Jest to podobne do odpowiedzi Zapha, ale zamiast pobierać jakąkolwiek wartość ze zwracania nowego indeksu (ponieważ zawsze będziemy mieć 1 sekcję), obliczamy indeks dla lokalizacji pierwszego elementu w tablicy, która zaczyna się od określonego znaku, a następnie przewijamy do tego.
Minusem jest to, że wymaga to przeszukiwania tablicy za każdym razem (czy to absolutnie okropne?), Jednak nie zauważyłem żadnego opóźnienia ani powolnego zachowania w symulatorze iOS ani na moim iPhonie 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; }
dodanie właściwości do przechowywania ostatnio wybranego indeksu, np
@property (assign, nonatomic) NSInteger previousSearchIndex;
i przechowywanie tej własności za każdym razem jak:
- (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; }
i aktualizowanie
scrollToRow
kodu, takiego jak:[tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
Zrób tę metodę jeszcze lepiej iz ładną animacją.
źródło
Grupa ludzi zapytała, czy można to zrobić bez sekcji. Chciałem tego samego i znalazłem rozwiązanie, które może być trochę podejrzane i nie zwraca wartości do sectionForSectionIndexTitle, ale jeśli jesteś w rogu i nie chcesz tworzyć sekcji dla każdej litery alfabetu, to to pewna poprawka. Przepraszam, że z góry szyfruję nazistów. : 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++; } }
Działa świetnie, jeśli otrzymujesz dużą ilość danych, a ich sekcje wymagałyby dużo pracy. :) Próbowałem użyć zmiennych ogólnych, żebyś wiedział, co robię. d_itemsInTable to NSArray z NSDictionaries, które wymieniam do UITableView.
źródło
Oto zmodyfikowana wersja funkcji Kyle'a, która obsługuje przypadek kliknięcia indeksu, dla którego nie masz ciągu:
- (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; }
źródło
Jeśli używasz
NSFetchedResultsController
, możesz po prostu:- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { return [frc sectionIndexTitles]; } - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { return [frc sectionForSectionIndexTitle:title atIndex:index]; }
źródło
Zaimplementuj metody delegata
-sectionIndexTitlesForTableView:
i-tableView:sectionForSectionIndexTitle:atIndex:
UITableViewDataSource
Więcej informacji można znaleźć w dokumentacji.źródło
Oto proste rozwiązanie w Swift, zakładając, że masz nagłówki tytułów w tablicy. Jeśli nie można znaleźć tytułu, zwróci poprzedni indeks w tablicy.
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 }
źródło
return self.headerTitles.count - self.headerTitles.filter{$0 > title}.count
aby zwracała indeks pierwszej, a nie ostatniej pasującej sekcji dla danego tytułu indeksu.Jeśli używasz MonoTouch, Zastąp metodę SectionIndexTitles (UITableView) w klasie UITableViewDataSource. Po prostu zwróć tablicę ciągów, a podklasa zajmie się resztą.
class TableViewDataSource : UITableViewDataSource { public override string[] SectionIndexTitles(UITableView tableView) { return new string[] { /*your string values */}; } }
* tylko wskazówka dla tych z nas, którzy używają C # i Mono (.NET) do pisania aplikacji na iPhone'a. :)
źródło