Dans l'application musicale iPhone, la sélection de l'artiste, des chansons ou des albums présente une tableView avec une liste verticale de lettres simples sur le côté droit de l'interface utilisateur qui permet un défilement rapide. Comment activer cette fonctionnalité dans mon application?
À la vôtre, Doug
Fournissez vos propres caractères d'index:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return[NSArray arrayWithObjects:@"a", @"e", @"i", @"m", @"p", nil];
}
et alors:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString
*)title atIndex:(NSInteger)index {
return <yourSectionIndexForTheSectionForSectionIndexTitle >;
}
Vous aurez besoin de sections.
Vous devez également considérer la localisation des sections pour chaque langue. Après avoir creusé un peu, j'ai trouvé que UILocalizedIndexedCollation
était très utile:
- (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
J'ai trouvé une approche alternative pour gérer une liste alphabétique à une seule lettre sans utiliser de sections. C'est similaire à la réponse de Zaph mais au lieu d'obtenir une valeur de retour d'un nouvel index (puisque nous aurons toujours 1 section), nous calculons l'index pour l'emplacement du premier élément du tableau qui commence par un certain caractère, puis faites défiler à elle.
L'inconvénient est que cela nécessite de rechercher le tableau à chaque fois (est-ce absolument terrible?), Mais je n'ai pas remarqué de retard ou de comportement lent dans le simulateur iOS ou sur mon 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;
}
ajout d'une propriété pour stocker le dernier index sélectionné comme
@property (assign, nonatomic) NSInteger previousSearchIndex;
et stocker cette propriété à chaque fois comme:
- (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;
}
et mettre à jour le code scrollToRow
comme:
[tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
Faites cette méthode encore mieux et avec une belle animation.
Un groupe de personnes a demandé s'il était possible de le faire sans sections. Je voulais la même chose et j'ai trouvé une solution qui pourrait être un peu louche et ne renvoie pas de valeur à sectionForSectionIndexTitle mais si vous êtes dans un coin et que vous ne voulez pas avoir à faire une section pour chaque lettre de l'alphabet, cela est une solution sûre. Désolé pour tout code Nazis à l'avance. : 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++;
}
}
Cela fonctionne très bien si vous obtenez une grande quantité de données et la sectionner nécessiterait beaucoup de travail. :) J'ai essayé d'utiliser des variables génériques pour que vous sachiez ce que je faisais. d_itemsInTable est un NSArray de NSDictionaries que j'énumère à UITableView.
Si vous utilisez un NSFetchedResultsController
, vous pouvez simplement faire:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [frc sectionIndexTitles];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [frc sectionForSectionIndexTitle:title atIndex:index];
}
Voici une version modifiée de la fonction de Kyle qui gère le cas de cliquer sur un index pour lequel vous n'avez pas de chaîne:
- (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;
}
Voici une solution simple dans Swift, en supposant que vous avez vos en-têtes de titre dans un tableau. Si le titre est introuvable, il renverra l'index précédent dans le tableau.
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
}
Implémentez les méthodes déléguées -sectionIndexTitlesForTableView:
et -tableView:sectionForSectionIndexTitle:atIndex:
Voir la documentation UITableViewDataSource
pour plus d'informations.
Si vous utilisez MonoTouch, remplacez la méthode SectionIndexTitles (UITableView) dans la classe UITableViewDataSource. Renvoyez simplement un tableau de chaînes et la sous-classe s'occupe du reste.
class TableViewDataSource : UITableViewDataSource
{
public override string[] SectionIndexTitles(UITableView tableView)
{
return new string[] { /*your string values */};
}
}
* juste un indice pour ceux d'entre nous qui utilisent C # et Mono (.NET) pour écrire des applications iPhone. :)