web-dev-qa-db-fra.com

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

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

81
dugla

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.

135
zaph

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

35
rwyland

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.

33
Kyle Clegg

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.

21
krut

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];
}
3
Snowman

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;
}
3
Danny

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
}
2
Samah

Implémentez les méthodes déléguées -sectionIndexTitlesForTableView: et -tableView:sectionForSectionIndexTitle:atIndex:

Voir la documentation UITableViewDataSource pour plus d'informations.

2
Alex Reynolds

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. :)

0
benhorgen