2013-08-06 21 views
8

Fatto frustrante: dopo aver chiamato tableView:moveRowAtIndexPath:toIndexPath:, tableView:cellForRowAtIndexPath: non viene chiamato per quella riga.Come ricaricare la riga spostata al livello di programmazione?

chiamata reloadRowsAtIndexPaths:withRowAnimation: dopo o prima tableView:moveRowAtIndexPath:toIndexPath: all'interno UITableView aggiornamenti bloccare anche non funziona: si genera l'errore Incoerenza.

Vedo 2 soluzioni: elimina + inserisci invece di spostare o ricaricare all'interno di un altro blocco di aggiornamenti.

La mia domanda è: c'è un altro modo per ricaricare e spostare la riga di UITableView all'interno dello stesso blocco di aggiornamenti?

risposta

4

Non penso sia possibile fare una mossa e una ricarica allo stesso tempo. Ho provato diversi approcci e la soluzione migliore che ho trovato è quella di eseguire il ricarico subito prima degli aggiornamenti batch. Non animare reloadRows perché sembra essere in conflitto con le animazioni di aggiornamento batch.

[tableView reloadRowsAtIndexPaths:indexPathsToReload withRowAnimation:UITableViewRowAnimationNone]; 
[tableView beginUpdates]; 
//inserts, deletes and moves here 
[tableView endUpdates]; 

Inoltre, io di solito messo la mia logica di configurazione cella in un metodo separato come:

- (void)tableView:(UITableView *)tableView configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; 

Così che io posso solo chiamare direttamente e bypass reloadRowsAtIndexPaths del tutto. Anche in questo caso non avrai l'animazione incorporata, ma puoi fare le tue animazioni.

+0

Questo sembra essere il modo migliore. Strano che il richiamo di 'reloadData' all'interno del blocco di aggiornamento annulli le animazioni. – devios1

0

Ho avuto successo con [TableView reloadData]. Assicurati di aggiornare l'origine dati e di inserire il codice di ricarica in un punto appropriato.

+2

Non c'è niente da fare con 'reloadData'. In realtà, il mio obiettivo principale è quello di eliminare 'reloadData', perché è brutto (ad es.lampeggiante) e interrompe gli utenti. – folex

0

Quando si sposta la cella è necessario per ottenere il cellulare direttamente tramite il metodo tableView.cellForRowAtIndexPath

Dopo aver preso il cellulare, basta aggiornarlo manualmente.

0
[_tableview beginUpdates]; 

// write code here to delete and move row... 

[_tableview endUpdates]; 

// now after end update call reload method to reload cell.. 

    [self.tableview reloadRowsAtIndexPaths:[NSArray arrayWithObjects: 
    [NSIndexPath indexPathForRow:_arrayForData.count-1 inSection:indexpathforSelectedRow.section], nil] withRowAnimation:UITableViewRowAnimationNone]; 
0

mi sono imbattuto in un problema simile quando sono ordinati su "DateModified", ma mi è stato anche la visualizzazione che la proprietà sull'etichetta della cellula. Sono stati richiesti sia "move" che "update". "move" è stato chiamato solo così la cella corretta è stata portata in cima alla lista, ma il testo dell'etichetta non è stato aggiornato.

La mia soluzione per un UITableViewCell semplice.

Innanzitutto, si effettua la chiamata .move normalmente. Subito dopo aver effettuato una chiamata a un metodo di configurazione personalizzato, che è responsabile dell'animazione dell'aggiornamento nella cella.

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { 
    switch type { 
    case .insert: 
     tableView.insertRows(at: [newIndexPath!], with: .fade) 
    case .delete: 
     tableView.deleteRows(at: [indexPath!], with: .fade) 
    case .update: 
     tableView.reloadRows(at: [indexPath!], with: .fade) 
    case .move: 
     tableView.moveRow(at: indexPath!, to: newIndexPath!) 

     // Can't "reload" and "move" to same cell simultaneously. 

     // This is an issue because I'm sorting on date modified and also displaying it within a 
     // label in the UITableViewCell. 

     // To have it look perfect you have to manually crossfade the label text, while the UITableView 
     // does the "move" animation. 

     let cell = tableView.cellForRow(at: indexPath!)! 
     let note = fetchedResultsController.object(at: newIndexPath!) 
     configure(cell: cell, note: note, animated: true) 
    } 
} 

Il metodo di configurazione è simile a questo (nota animato è opzionale):

internal func configure(cell: UITableViewCell, note: Note, animated: Bool = false) { 
    let dateFormatter = DateFormatter() 
    dateFormatter.dateStyle = .medium 
    dateFormatter.timeStyle = .medium 
    let dateString = dateFormatter.string(from: note.dateModified as Date) 

    if animated { 
     UIView.transition(with: cell.contentView, duration: 0.3, options: .transitionCrossDissolve, animations: { 
      cell.textLabel?.text = dateString 
     }, completion: nil) 
    } else { 
     cell.textLabel?.text = dateString 
    } 
} 

riutilizzare il metodo configure qui senza animazione:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifier, for: indexPath) 
    let note = fetchedResultsController.object(at: indexPath) 

    configure(cell: cell, note: note) 

    return cell 
} 

Se si dispone di una cella più complicata (sottoclasse), potresti probabilmente spostare il metodo configure nel codice della sottoclasse. La parte importante è avere un metodo per aggiornare i dati della cella con l'animazione opzionale.

Problemi correlati