81 votes

iPhone UITableView. Comment activer la liste alphabétique à une seule lettre comme dans l'application Musique ?

Dans l'application musicale de l'iPhone, le fait de sélectionner Artiste, Chansons ou Albums présente une tableView avec une liste verticale de lettres simples sur le côté droit de l'interface utilisateur, ce qui permet un défilement rapide. Comment puis-je activer cette fonctionnalité dans mon application ?

A la vôtre, Doug

135voto

Zaph Points 40557

Fournissez vos propres caractères d'index :

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return[NSArray arrayWithObjects:@"a", @"e", @"i", @"m", @"p", nil];
}

et ensuite :

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString
    *)title atIndex:(NSInteger)index {
        return <yourSectionIndexForTheSectionForSectionIndexTitle >;
}

Vous aurez besoin de sections.

35voto

rwyland Points 887

Il faut également penser à localiser les sections pour chaque langue. Après avoir creusé un peu, j'ai trouvé UILocalizedIndexedCollation pour être 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

33voto

Kyle Clegg Points 8441

J'ai trouvé une autre approche pour gérer une liste alphabétique d'une seule lettre sans utiliser de sections. C'est similaire à la réponse de Zaph, mais au lieu d'obtenir une valeur en retournant un nouvel index (puisque nous aurons toujours une section), nous calculons l'index pour l'emplacement du premier élément du tableau qui commence par un certain caractère, puis nous le faisons défiler.

L'inconvénient est que cela nécessite de rechercher le tableau à chaque fois (n'est-ce pas absolument terrible ?), mais je n'ai pas remarqué de décalage ou de lenteur 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;
}

ajouter une propriété pour stocker le dernier index sélectionné comme

 @property (assign, nonatomic) NSInteger previousSearchIndex;

et en stockant 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 la mise à jour scrollToRow comme un code :

 [tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];

Faites cette méthode encore mieux et avec une belle animation.

21voto

krut Points 212

Un certain nombre de personnes ont demandé s'il était possible de faire cela sans sections. Je voulais la même chose et j'ai trouvé une solution qui peut être un peu louche et qui ne renvoie pas de valeur à sectionForSectionIndexTitle mais si vous êtes dans un coin et ne voulez pas avoir à faire une section pour chaque lettre de l'alphabet, c'est une solution sûre. Désolé d'avance pour les nazis du code :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 que le découpage en sections 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 je liste dans le UITableView.

3voto

Danny Points 131

Voici une version modifiée de la fonction de Kyle qui gère le cas où vous cliquez 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;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X