2012-06-09 16 views
13

Ho un UITableView popolato con un NSFetchedResultsController standard. Tuttavia preferirei anteporre una riga o una sezione (preferibilmente una riga, ma funzionerebbe davvero bene).NSFetchedResultsController anteporre una riga o una sezione

L'unico modo in cui è possibile vedere in questo momento è quello di riscrivere manualmente tutto NSIndexPath quando si ha a che fare con la sezione/righe che si occupano dei dati di NSFetchedResultsController per indurli a vedere la sezione nell'indice 0 e iniziare con la riga all'indice 0. Questa sembra comunque una pessima idea che potrebbe facilmente confondersi e quindi preferirei evitarlo.

Un buon esempio di questo sarebbe nell'app ufficiale di Twitter quando si avvia per la prima volta e vi accompagna aggiungendo alcune persone dalla vostra lista di amici.

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

La sezione rossa è più o meno quello che mi piacerebbe realizzare, e la sezione gialla presumo sia i risultati di un NSFetchedResultsController nella stessa sezione (anche se con il loro stile personalizzato potrebbe essere un separato sezione.)

+0

possibile duplicato del [Aggiungi riga in più per un UITableView gestito da NSFetchedResultsController] (http://stackoverflow.com/questions/ 9604410/add-extra-row-to-a-uitableview-managed-by-nsfetchedresultscontroller) – JosephH

risposta

31

Questo è possibile fare in modo abbastanza pulito.

Suppongo che tu stia iniziando con una tabella standard impostata con un NSFetchResultsController standard che utilizza il codice di esempio di Apple.

In primo luogo avete bisogno di due funzioni di utilità:

- (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; 
} 

Questi dovrebbero essere abbastanza autoesplicativo - sono solo aiutanti per affrontare con l'aggiunta della riga in più quando si vuole utilizzare un percorso di indice dai controllori risultati recuperati per accedere al tavolo o rimuoverlo quando si passa dall'altra parte.

Poi abbiamo bisogno di creare la cellula in più:

- (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; 
} 

assicurarsi configuriamo correttamente (configurecell sarà chiamato solo per le cellule provenienti dal controllore recuperare i risultati):

// 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 ...> 
} 

e raccontare esiste la tabella:

- (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; 
} 

e rispondere alla selezione:

- (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 ... 

e poi rimappare tutti gli aggiornamenti che otteniamo dal controller risultati:

- (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

Se in questo approccio, mi piace cancellare in modo dinamico la prima riga sarà possibile. – cocoaNoob

+0

@cocoaNoob Sì, funzionerebbe bene. Finché esegui correttamente il mapping di indexPath, puoi fare praticamente qualsiasi cosa. – JosephH

+0

Sì, l'ho provato invece di usare 1, sto usando la variabile di istanza. Un approccio molto buono e chiaro. Grazie per aver condiviso la tua soluzione @JosepH. – cocoaNoob

3

Capisco le vostre preoccupazioni sulla complessità, ma in realtà è solo aggiungendo 1 a numberOfRowsInSection: e aggiungendo 1 a indexPath.row in cellForRowAtIndexPath: (accanto all'aggiunta del codice per la riga 0).

Un'altra soluzione non dovrebbe essere molto elaborata per diventare ancora più ingombrante.

Detto questo, sembra davvero che la "voce" che si propone sia un tipico candidato per un'intestazione di sezione .

+0

Questo è un buon punto, stavo principalmente controllando se non esistesse un metodo che non conoscevo su NSFetchedResultsController che ti lasciava precedere o aggiungi un insieme di righe ai risultati che restituisce in modo da poterli personalizzare. –

Problemi correlati