2012-06-09 4 views
13

J'ai une UITableView remplie avec un NSFetchedResultsController standard. Cependant, je voudrais préfixer une ligne ou une section (rangée de préférence, mais l'une ou l'autre fonctionnerait vraiment très bien.)NSFetchedResultsController ajoute une ligne ou une section

La seule façon que je peux éventuellement voir faire ceci maintenant est de réécrire tous les NSIndexPath manuellement en traitant de la section/rows traitant les données de NSFetchedResultsController pour tromper en voyant la section à l'index 0 et en commençant par la ligne à l'index 0. Cela semble toutefois être une très mauvaise idée qui serait rapidement confuse, donc je préfère éviter cela.

Un bon exemple de ceci serait dans l'application officielle de Twitter quand vous le démarrez pour la première fois et je vous guide en ajoutant des personnes de votre liste d'amis.

Screenshot of Twitter app's suggestions page, with the relevant sections highlighted

La section rouge est à peu près ce que je voudrais réaliser, et la section jaune je suppose est le résultat d'une NSFetchedResultsController dans la même section (bien que leur style personnalisé, il pourrait être séparé section.)

+0

double possible de [Ajouter une ligne supplémentaire à un UITableView géré par NSFetchedResultsController] (http://stackoverflow.com/questions/ 9604410/add-extra-row-to-a-view-managed-by-nsfetchedresultscontroller) – JosephH

Répondre

31

Ceci est possible de faire d'une manière assez propre.

Je suppose que vous démarrez avec une tableview standard configurée avec un NSFetchResultsController standard qui utilise l'exemple de code d'Apple.

D'abord, vous avez besoin de deux fonctions utilitaires:

- (NSIndexPath *)mapIndexPathFromFetchResultsController:(NSIndexPath *)indexPath 
{ 
    if (indexPath.section == 0) 
     indexPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section]; 

    return indexPath; 
} 

- (NSIndexPath *)mapIndexPathToFetchResultsController:(NSIndexPath *)indexPath 
{ 
    if (indexPath.section == 0) 
     indexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section]; 

    return indexPath; 
} 

Ces devrait être assez explicite - ils sont juste des aides pour faire face à l'ajout de la ligne supplémentaire lorsque l'on veut utiliser un chemin d'index des contrôleurs récupérés résultats pour accéder à la table, ou l'enlever en allant dans l'autre sens.

Ensuite, nous avons besoin de créer la cellule supplémentaire:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    static NSString *CellIdentifier = @"MyCellId"; 

    if (indexPath.section == 0 && indexPath.row == 0) 
    { 
     UITableViewCell *cell; 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; 
     cell.selectionStyle = UITableViewCellSelectionStyleGray; 
     cell.textLabel.text = NSLocalizedString(@"Extra cell text", nil); 

     return cell; 
    } 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; 
    } 

    [self configureCell:cell atIndexPath:indexPath]; 

    return cell; 
} 

assurez-vous que nous configurons correctement (configurecell ne sera appelé pour les cellules du contrôleur résultats fetch):

// the indexPath parameter here is the one for the table; ie. it's offset from the fetched result controller's indexes 
- (void)configureCell:(SyncListViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { 
    indexPath = [self mapIndexPathToFetchResultsController:indexPath]; 

    id *obj = [fetchedResultsController objectAtIndexPath:indexPath]; 
    <... perform normal cell setup ...> 
} 

et dire la tableview existe:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    NSInteger numberOfRows = 0; 

    if ([[fetchedResultsController sections] count] > 0) { 
     id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; 
     numberOfRows = [sectionInfo numberOfObjects]; 
    } 

    if (section == 0) 
     numberOfRows++; 

    return numberOfRows; 
} 

et répondez à la sélection:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 

    if (indexPath.section == 0 && indexPath.row == 0) 
    { 
     [self doExtraAction]; 
     return; 
    } 

    ... deal with selection for other cells ... 

et remappez alors toutes les mises à jour que nous obtenons du contrôleur de résultats:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 
    UITableView *tableView = self.tableView; 

    indexPath = [self mapIndexPathFromFetchResultsController:indexPath]; 
    newIndexPath = [self mapIndexPathFromFetchResultsController:newIndexPath]; 

    switch(type) { 
     ... handle as normal ... 
+0

Si dans cette approche, j'aime supprimer dynamiquement la première rangée, cela sera possible. – cocoaNoob

+0

@cocoaNoob Oui, cela fonctionnerait bien. Tant que vous mappez l'indexPath correctement, vous pouvez faire pratiquement n'importe quoi. – JosephH

+0

Oui, je l'ai essayé au lieu d'utiliser 1, j'utilise une variable d'instance. Une approche très bonne et claire. Merci de partager votre solution @JosepH. – cocoaNoob

3

Je comprends vos préoccupations au sujet de la complexité, mais il est vraiment juste d'ajouter 1-numberOfRowsInSection: et en ajoutant 1-indexPath.row dans cellForRowAtIndexPath: (à côté de l'ajout du code pour la ligne 0).

Une autre solution n'aurait pas besoin d'être très élaborée pour devenir encore plus encombrante. Cela étant dit, il semble vraiment que le «titre» que vous proposez soit un candidat typique pour un en-tête de section.

+0

C'est un bon point, je vérifiais surtout s'il n'y avait pas une méthode que je ne connaissais pas sur NSFetchedResultsController qui vous laisse préfixer ou ajoutez un ensemble de lignes aux résultats renvoyés afin de les personnaliser. –

Questions connexes